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
|
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
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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)]
|
||||||
|
@ -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 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
})
|
}))
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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#"
|
||||||
|
Loading…
Reference in New Issue
Block a user