Compare commits
2 Commits
9de1b4ea33
...
63ef1451d9
Author | SHA1 | Date | |
---|---|---|---|
|
63ef1451d9 | ||
|
e40782739d |
4
TODO.md
4
TODO.md
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)]
|
||||
|
@ -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 })
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
})
|
||||
}))
|
||||
}),
|
||||
]
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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#"
|
||||
|
Loading…
Reference in New Issue
Block a user