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 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 ## Parser
* I think I can restructure the parser to get rid of most instances of expect!, at least at the beginning of a rule * 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 Option<T> = Some(T) | None
type Ord = LT | EQ | GT 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> { fn map(input: Option<T>, func: Func): Option<T> {
if input { if input {

View File

@ -53,6 +53,7 @@ pub enum StatementKind {
Expression(Expression), Expression(Expression),
Declaration(Declaration), Declaration(Declaration),
Import(ImportSpecifier), Import(ImportSpecifier),
//TODO maybe modules shoudl be a type of declaration
Module(ModuleSpecifier), Module(ModuleSpecifier),
Flow(FlowControl), Flow(FlowControl),
} }
@ -130,7 +131,8 @@ pub enum Declaration {
Binding { name: Rc<String>, constant: bool, type_anno: Option<TypeIdentifier>, expr: Expression }, Binding { name: Rc<String>, constant: bool, type_anno: Option<TypeIdentifier>, expr: Expression },
Impl { type_name: TypeIdentifier, interface_name: Option<TypeSingletonName>, block: Vec<Declaration> }, Impl { type_name: TypeIdentifier, interface_name: Option<TypeSingletonName>, block: Vec<Declaration> },
Interface { name: Rc<String>, signatures: Vec<Signature> }, 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)] #[derive(Debug, PartialEq, Clone)]

View File

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

View File

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

View File

@ -4,13 +4,14 @@ use std::{
collections::{hash_map::Entry, HashMap, HashSet}, collections::{hash_map::Entry, HashMap, HashSet},
fmt, fmt,
rc::Rc, rc::Rc,
str::FromStr,
}; };
use crate::{ use crate::{
ast, ast,
ast::{ ast::{
Declaration, ItemId, ModuleSpecifier, Statement, StatementKind, TypeBody, TypeSingletonName, Variant, Declaration, Expression, ExpressionKind, ItemId, ModuleSpecifier, Statement, StatementKind, TypeBody,
VariantKind, TypeSingletonName, Variant, VariantKind,
}, },
builtin::Builtin, builtin::Builtin,
tokenizing::Location, tokenizing::Location,
@ -43,6 +44,7 @@ impl Fqsn {
Fqsn { scopes: v } Fqsn { scopes: v }
} }
#[allow(dead_code)]
fn from_strs(strs: &[&str]) -> Fqsn { fn from_strs(strs: &[&str]) -> Fqsn {
let mut scopes = vec![]; let mut scopes = vec![];
for s in strs { for s in strs {
@ -51,7 +53,7 @@ impl Fqsn {
Fqsn { scopes } Fqsn { scopes }
} }
fn local_name(&self) -> Rc<String> { fn last_elem(&self) -> Rc<String> {
let ScopeSegment::Name(name) = self.scopes.last().unwrap(); let ScopeSegment::Name(name) = self.scopes.last().unwrap();
name.clone() name.clone()
} }
@ -89,6 +91,8 @@ pub enum SymbolError {
DuplicateName { prev_name: Fqsn, location: Location }, DuplicateName { prev_name: Fqsn, location: Location },
DuplicateVariant { type_fqsn: Fqsn, name: String }, DuplicateVariant { type_fqsn: Fqsn, name: String },
DuplicateRecord { type_name: Fqsn, location: Location, member: String }, DuplicateRecord { type_name: Fqsn, location: Location, member: String },
UnknownAnnotation { name: String },
BadAnnotation { name: String, msg: String },
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -221,11 +225,13 @@ impl SymbolTable {
} }
fn populate_builtins(&mut self) { fn populate_builtins(&mut self) {
/*
let fqsn = Fqsn::from_strs(&["println"]); let fqsn = Fqsn::from_strs(&["println"]);
self.populate_single_builtin(fqsn, Builtin::IOPrintLn); self.populate_single_builtin(fqsn, Builtin::IOPrintLn);
let fqsn = Fqsn::from_strs(&["print"]); let fqsn = Fqsn::from_strs(&["print"]);
self.populate_single_builtin(fqsn, Builtin::IOPrint); self.populate_single_builtin(fqsn, Builtin::IOPrint);
*/
} }
} }
@ -244,7 +250,7 @@ pub struct Symbol {
impl Symbol { impl Symbol {
pub fn local_name(&self) -> Rc<String> { 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> { 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()); let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone());
self.table.fq_names.register(fq_module, NameSpec { location, kind: NameKind::Module })?; 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(()) 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( fn add_type_members(
&mut self, &mut self,
type_name: &TypeSingletonName, type_name: &TypeSingletonName,

View File

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

View File

@ -78,6 +78,44 @@ fn scopes() {
eval_assert(scope_ok, "20"); 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] #[test]
fn adt_output_1() { fn adt_output_1() {
let source = r#" let source = r#"