Compare commits

...

2 Commits

Author SHA1 Message Date
Greg Shuflin
63ef1451d9 Fix bug with nested function scopes 2021-11-02 18:07:08 -07:00
Greg Shuflin
e40782739d Use annotations to mark builtins 2021-11-02 16:56:12 -07:00
8 changed files with 134 additions and 17 deletions

View File

@ -23,10 +23,6 @@
2. Once FQSNs are aware of function parameters, most of the Rc<String> things in eval.rs can go away
## Semantics
* Use annotations to indicate builtin functions
## Parser
* I think I can restructure the parser to get rid of most instances of expect!, at least at the beginning of a rule

View File

@ -3,6 +3,14 @@ let _SCHALA_VERSION = "0.1.0"
type Option<T> = Some(T) | None
type Ord = LT | EQ | GT
@register_builtin(print)
fn print(arg) { }
@register_builtin(println)
fn println(arg) { }
@register_builtin(getline)
fn getline(arg) { }
fn map(input: Option<T>, func: Func): Option<T> {
if input {

View File

@ -53,6 +53,7 @@ pub enum StatementKind {
Expression(Expression),
Declaration(Declaration),
Import(ImportSpecifier),
//TODO maybe modules shoudl be a type of declaration
Module(ModuleSpecifier),
Flow(FlowControl),
}
@ -130,7 +131,8 @@ pub enum Declaration {
Binding { name: Rc<String>, constant: bool, type_anno: Option<TypeIdentifier>, expr: Expression },
Impl { type_name: TypeIdentifier, interface_name: Option<TypeSingletonName>, block: Vec<Declaration> },
Interface { name: Rc<String>, signatures: Vec<Signature> },
Annotation { name: Rc<String>, arguments: Vec<Expression>, inner: Box<Declaration> },
//TODO need to limit the types of statements that can be annotated
Annotation { name: Rc<String>, arguments: Vec<Expression>, inner: Box<Statement> },
}
#[derive(Debug, PartialEq, Clone)]

View File

@ -445,7 +445,7 @@ impl Parser {
if let Semicolon | Newline = self.token_handler.peek_kind() {
self.token_handler.next();
}
let inner = Box::new(self.declaration()?);
let inner = Box::new(self.statement()?);
Ok(Declaration::Annotation { name, arguments, inner })
}

View File

@ -928,10 +928,10 @@ fn impls() {
fn annotations() {
use ExpressionKind::*;
let func = Declaration::FuncDecl(
let func = decl(Declaration::FuncDecl(
Signature { name: rc("some_function"), operator: false, params: vec![], type_anno: None },
vec![].into(),
);
));
assert_ast! {
r#"
@ -957,9 +957,9 @@ fn annotations() {
vec![decl(Declaration::Annotation {
name: rc("test_annotation"),
arguments: vec![expr(Value(qn!(some))), expr(Value(qn!(value)))],
inner: bx(Declaration::Annotation {
inner: bx(decl(Declaration::Annotation {
name: rc("another_annotation"), arguments: vec![], inner: bx(func)
})
}))
}),
]
};

View File

@ -4,13 +4,14 @@ use std::{
collections::{hash_map::Entry, HashMap, HashSet},
fmt,
rc::Rc,
str::FromStr,
};
use crate::{
ast,
ast::{
Declaration, ItemId, ModuleSpecifier, Statement, StatementKind, TypeBody, TypeSingletonName, Variant,
VariantKind,
Declaration, Expression, ExpressionKind, ItemId, ModuleSpecifier, Statement, StatementKind, TypeBody,
TypeSingletonName, Variant, VariantKind,
},
builtin::Builtin,
tokenizing::Location,
@ -43,6 +44,7 @@ impl Fqsn {
Fqsn { scopes: v }
}
#[allow(dead_code)]
fn from_strs(strs: &[&str]) -> Fqsn {
let mut scopes = vec![];
for s in strs {
@ -51,7 +53,7 @@ impl Fqsn {
Fqsn { scopes }
}
fn local_name(&self) -> Rc<String> {
fn last_elem(&self) -> Rc<String> {
let ScopeSegment::Name(name) = self.scopes.last().unwrap();
name.clone()
}
@ -89,6 +91,8 @@ pub enum SymbolError {
DuplicateName { prev_name: Fqsn, location: Location },
DuplicateVariant { type_fqsn: Fqsn, name: String },
DuplicateRecord { type_name: Fqsn, location: Location, member: String },
UnknownAnnotation { name: String },
BadAnnotation { name: String, msg: String },
}
#[allow(dead_code)]
@ -221,11 +225,13 @@ impl SymbolTable {
}
fn populate_builtins(&mut self) {
/*
let fqsn = Fqsn::from_strs(&["println"]);
self.populate_single_builtin(fqsn, Builtin::IOPrintLn);
let fqsn = Fqsn::from_strs(&["print"]);
self.populate_single_builtin(fqsn, Builtin::IOPrint);
*/
}
}
@ -244,7 +250,7 @@ pub struct Symbol {
impl Symbol {
pub fn local_name(&self) -> Rc<String> {
self.fully_qualified_name.local_name()
self.fully_qualified_name.last_elem()
}
pub fn def_id(&self) -> Option<DefId> {
@ -411,11 +417,68 @@ impl<'a> SymbolTableRunner<'a> {
let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone());
self.table.fq_names.register(fq_module, NameSpec { location, kind: NameKind::Module })?;
}
StatementKind::Declaration(Declaration::Annotation { name, arguments, inner }) => {
let inner = inner.as_ref();
self.add_single_statement(
&inner.id,
&inner.kind,
inner.location,
scope_stack,
function_scope,
)?;
self.process_annotation(name.as_ref(), arguments.as_slice(), scope_stack, inner)?;
}
_ => (),
}
Ok(())
}
fn process_annotation(
&mut self,
name: &str,
arguments: &[Expression],
scope_stack: &[ScopeSegment],
inner: &Statement,
) -> Result<(), SymbolError> {
println!("handling annotation: {}", name);
if name == "register_builtin" {
if let Statement {
id: _,
location: _,
kind: StatementKind::Declaration(Declaration::FuncDecl(sig, _)),
} = inner
{
let fqsn = Fqsn::from_scope_stack(scope_stack, sig.name.clone());
let builtin_name = match arguments {
[Expression { kind: ExpressionKind::Value(qname), .. }]
if qname.components.len() == 1 =>
qname.components[0].clone(),
_ =>
return Err(SymbolError::BadAnnotation {
name: name.to_string(),
msg: "Bad argument for register_builtin".to_string(),
}),
};
let builtin =
Builtin::from_str(builtin_name.as_str()).map_err(|_| SymbolError::BadAnnotation {
name: name.to_string(),
msg: format!("Invalid builtin: {}", builtin_name),
})?;
self.table.populate_single_builtin(fqsn, builtin);
Ok(())
} else {
Err(SymbolError::BadAnnotation {
name: name.to_string(),
msg: "register_builtin not annotating a function".to_string(),
})
}
} else {
Err(SymbolError::UnknownAnnotation { name: name.to_string() })
}
}
fn add_type_members(
&mut self,
type_name: &TypeSingletonName,

View File

@ -11,6 +11,7 @@ enum NameType {
//TODO eventually this needs to support closures
Param(u8), //TODO handle implications of functions being limited to 255 params
LocalVariable(ItemId),
LocalFunction(ItemId),
Import(Fqsn),
}
@ -67,6 +68,13 @@ impl<'a> ScopeResolver<'a> {
let fqsn = Fqsn { scopes: vec![lscope, ScopeSegment::Name(local_name.clone())] };
self.symbol_table.add_symbol(id, fqsn, spec);
}
Some(NameType::LocalFunction(item_id)) => {
let def_id = self.symbol_table.id_to_def.get(item_id);
if let Some(def_id) = def_id {
let def_id = def_id.clone();
self.symbol_table.id_to_def.insert(*id, def_id);
}
}
Some(NameType::LocalVariable(item_id)) => {
let def_id = self.symbol_table.id_to_def.get(item_id);
if let Some(def_id) = def_id {
@ -99,13 +107,13 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
Fqsn { scopes: path_components.iter().map(|c| ScopeSegment::Name(c.clone())).collect() };
let members = self.symbol_table.symbol_trie.get_children(&prefix);
for fqsn in members.into_iter() {
self.lexical_scopes.insert(fqsn.local_name(), NameType::Import(fqsn));
self.lexical_scopes.insert(fqsn.last_elem(), NameType::Import(fqsn));
}
}
ImportedNames::LastOfPath => {
let fqsn =
Fqsn { scopes: path_components.iter().map(|c| ScopeSegment::Name(c.clone())).collect() };
self.lexical_scopes.insert(fqsn.local_name(), NameType::Import(fqsn));
self.lexical_scopes.insert(fqsn.last_elem(), NameType::Import(fqsn));
}
ImportedNames::List(ref names) => {
let fqsn_prefix: Vec<ScopeSegment> =
@ -114,7 +122,7 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
let mut scopes = fqsn_prefix.clone();
scopes.push(ScopeSegment::Name(name.clone()));
let fqsn = Fqsn { scopes };
self.lexical_scopes.insert(fqsn.local_name(), NameType::Import(fqsn));
self.lexical_scopes.insert(fqsn.last_elem(), NameType::Import(fqsn));
}
}
};
@ -139,6 +147,8 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
new_scope.insert(param, NameType::Param(n as u8));
}
self.lexical_scopes.insert(signature.name.clone(), NameType::LocalFunction(*id));
let mut new_resolver =
ScopeResolver { symbol_table: self.symbol_table, lexical_scopes: new_scope };
walk_block(&mut new_resolver, block);

View File

@ -78,6 +78,44 @@ fn scopes() {
eval_assert(scope_ok, "20");
}
#[test]
fn eval_scopes_2() {
eval_assert(
r#"
fn trad() {
let a = 10
fn jinner() {
let b = 20
b
}
a + jinner()
}
trad()"#,
"30",
);
let err =
"No symbol found for name: QualifiedName { id: Id { idx: 4, t: PhantomData }, components: [\"a\"] }";
eval_assert_failure(
r#"
fn trad() {
let a = 10
fn inner() {
let b = 20
a + b
}
inner()
}
trad()
"#,
err,
);
}
#[test]
fn adt_output_1() {
let source = r#"