diff --git a/schala-lang/language/src/ast.rs b/schala-lang/language/src/ast.rs
index dd4840f..cdd9175 100644
--- a/schala-lang/language/src/ast.rs
+++ b/schala-lang/language/src/ast.rs
@@ -46,6 +46,9 @@ pub enum Statement {
pub type Block = Vec>;
pub type ParamName = Rc;
+#[derive(Debug, PartialEq, Clone)]
+pub struct QualifiedName(pub Vec>);
+
#[derive(Debug, PartialEq, Clone)]
pub struct FormalParam {
pub name: ParamName,
@@ -138,9 +141,9 @@ pub enum ExpressionKind {
BinExp(BinOp, Box>, Box>),
PrefixExp(PrefixOp, Box>),
TupleLiteral(Vec>),
- Value(Rc),
+ Value(QualifiedName),
NamedStruct {
- name: Rc,
+ name: QualifiedName,
fields: Vec<(Rc, Meta)>,
},
Call {
diff --git a/schala-lang/language/src/parsing.rs b/schala-lang/language/src/parsing.rs
index 26b83a5..7e68045 100644
--- a/schala-lang/language/src/parsing.rs
+++ b/schala-lang/language/src/parsing.rs
@@ -85,13 +85,14 @@
//! lambda_param_list := formal_param_list | formal_param
//! paren_expr := "(" paren_inner ")"
//! paren_inner := (expression ",")*
-//! identifier_expr := named_struct | IDENTIFIER
+//! identifier_expr := qualified_identifier | named_struct
+//! qualified_identifier := IDENTIFIER ("::" IDENTIFIER)*
//! ```
//!
//! ## Literals
//! ```text
//! literal := "true" | "false" | number_literal | STR_LITERAL
-//! named_struct := IDENTIFIER record_block
+//! named_struct := qualified_identifier record_block
//! record_block := "{" (record_entry, ",")* | "}" //TODO support anonymus structs, update syntax
//! record_entry := IDENTIFIER ":" expression
//! anonymous_struct := TODO
@@ -213,6 +214,7 @@ impl TokenHandler {
fn peek(&mut self) -> Token {
self.tokens.get(self.idx).map(|t: &Token| { t.clone()}).unwrap_or(Token { kind: TokenKind::EOF, line_num: self.end_of_file.0, char_num: self.end_of_file.1})
}
+ /// calling peek_n(0) is the same thing as peek()
fn peek_n(&mut self, n: usize) -> Token {
self.tokens.get(self.idx + n).map(|t: &Token| { t.clone()}).unwrap_or(Token { kind: TokenKind::EOF, line_num: self.end_of_file.0, char_num: self.end_of_file.1})
}
@@ -757,16 +759,31 @@ impl Parser {
#[recursive_descent_method]
fn identifier_expr(&mut self) -> ParseResult {
use self::ExpressionKind::*;
- let identifier = self.identifier()?;
+ let qualified_identifier = self.qualified_identifier()?;
Ok(match self.token_handler.peek_kind() {
LCurlyBrace if !self.restrictions.no_struct_literal => {
let fields = self.record_block()?;
- Expression::new(NamedStruct { name: identifier, fields })
+ Expression::new(NamedStruct { name: qualified_identifier, fields })
},
- _ => Expression::new(Value(identifier))
+ _ => Expression::new(Value(qualified_identifier))
})
}
+ #[recursive_descent_method]
+ fn qualified_identifier(&mut self) -> ParseResult {
+ let mut vec = vec![self.identifier()?];
+ loop {
+ match (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
+ (Colon, Colon) => {
+ self.token_handler.next(); self.token_handler.next();
+ vec.push(self.identifier()?);
+ },
+ _ => break,
+ }
+ }
+ Ok(QualifiedName(vec))
+ }
+
#[recursive_descent_method]
fn record_block(&mut self) -> ParseResult, Meta)>> {
Ok(
diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs
index 33363eb..ab07aec 100644
--- a/schala-lang/language/src/parsing/test.rs
+++ b/schala-lang/language/src/parsing/test.rs
@@ -4,7 +4,7 @@ use std::str::FromStr;
use super::tokenize;
use super::ParseResult;
-use crate::ast::{AST, Meta, Expression, Statement, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam, PrefixOp, BinOp};
+use crate::ast::{AST, Meta, Expression, Statement, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam, PrefixOp, BinOp, QualifiedName};
use super::Statement::*;
use super::Declaration::*;
use super::Signature;
@@ -30,7 +30,7 @@ macro_rules! parse_error {
($string:expr) => { assert!(parse($string).is_err()) }
}
macro_rules! val {
- ($var:expr) => { Value(Rc::new($var.to_string())) }
+ ($var:expr) => { Value(QualifiedName(vec![Rc::new($var.to_string())])) };
}
macro_rules! ty {
($name:expr) => { Singleton(tys!($name)) }
@@ -153,11 +153,11 @@ fn parsing_identifiers() {
parse_test!("None", AST(vec![exst!(val!("None"))]));
parse_test!("Pandas { a: x + y }", AST(vec![
- exst!(NamedStruct { name: rc!(Pandas), fields: vec![(rc!(a), ex!(m binexp!("+", val!("x"), val!("y"))))]})
+ exst!(NamedStruct { name: QualifiedName(vec![rc!(Pandas)]), fields: vec![(rc!(a), ex!(m binexp!("+", val!("x"), val!("y"))))]})
]));
parse_test! { "Pandas { a: n, b: q, }",
AST(vec![
- exst!(NamedStruct { name: rc!(Pandas), fields:
+ exst!(NamedStruct { name: QualifiedName(vec![rc!(Pandas)]), fields:
vec![(rc!(a), ex!(m val!("n"))), (rc!(b), ex!(m val!("q")))]
}
)
diff --git a/schala-lang/language/src/reduced_ast.rs b/schala-lang/language/src/reduced_ast.rs
index 5b58a1a..bf1153d 100644
--- a/schala-lang/language/src/reduced_ast.rs
+++ b/schala-lang/language/src/reduced_ast.rs
@@ -16,7 +16,7 @@ use std::rc::Rc;
use std::str::FromStr;
use crate::ast::*;
-use crate::symbol_table::{Symbol, SymbolSpec, SymbolTable};
+use crate::symbol_table::{Symbol, SymbolSpec, SymbolTable, ScopeSegment, ScopeSegmentKind, FullyQualifiedSymbolName};
use crate::builtin::Builtin;
#[derive(Debug)]
@@ -142,6 +142,21 @@ impl InvocationArgument {
}
}
+//TODO this is incomplete
+fn lookup_name_in_scope(sym_name: &QualifiedName) -> FullyQualifiedSymbolName {
+ let QualifiedName(vec) = sym_name;
+ let len = vec.len();
+ let new_vec: Vec = vec.iter().enumerate().map(|(i, name)| {
+ let kind = if i == (len - 1) {
+ ScopeSegmentKind::Terminal
+ } else {
+ ScopeSegmentKind::Type
+ };
+ ScopeSegment { name: name.clone(), kind }
+ }).collect();
+ FullyQualifiedSymbolName(new_vec)
+}
+
impl Expression {
fn reduce(&self, symbol_table: &SymbolTable) -> Expr {
use crate::ast::ExpressionKind::*;
@@ -153,14 +168,19 @@ impl Expression {
BoolLiteral(b) => Expr::Lit(Lit::Bool(*b)),
BinExp(binop, lhs, rhs) => binop.reduce(symbol_table, lhs, rhs),
PrefixExp(op, arg) => op.reduce(symbol_table, arg),
- Value(name) => match symbol_table.lookup_by_name(name) {
- Some(Symbol { spec: SymbolSpec::DataConstructor { index, type_args, type_name}, .. }) => Expr::Constructor {
- type_name: type_name.clone(),
- name: name.clone(),
- tag: index.clone(),
- arity: type_args.len(),
- },
- _ => Expr::Sym(name.clone()),
+ Value(qualified_name) => {
+ let sym_name = lookup_name_in_scope(&qualified_name);
+ let FullyQualifiedSymbolName(ref v) = sym_name;
+ let name = v.last().unwrap().name.clone();
+ match symbol_table.lookup_by_fqsn(&sym_name) {
+ Some(Symbol { spec: SymbolSpec::DataConstructor { index, type_args, type_name}, .. }) => Expr::Constructor {
+ type_name: type_name.clone(),
+ name: name.clone(),
+ tag: index.clone(),
+ arity: type_args.len(),
+ },
+ _ => Expr::Sym(name.clone()),
+ }
},
Call { f, arguments } => reduce_call_expression(f, arguments, symbol_table),
TupleLiteral(exprs) => Expr::Tuple(exprs.iter().map(|e| e.node().reduce(symbol_table)).collect()),
@@ -183,8 +203,12 @@ fn reduce_lambda(params: &Vec, body: &Block, symbol_table: &SymbolT
})
}
-fn reduce_named_struct(name: &Rc, fields: &Vec<(Rc, Meta)>, symbol_table: &SymbolTable) -> Expr {
- let (type_name, index, members_from_table) = match symbol_table.lookup_by_name(name) {
+fn reduce_named_struct(name: &QualifiedName, fields: &Vec<(Rc, Meta)>, symbol_table: &SymbolTable) -> Expr {
+
+ let sym_name = lookup_name_in_scope(name);
+ let FullyQualifiedSymbolName(ref v) = sym_name;
+ let ref name = v.last().unwrap().name;
+ let (type_name, index, members_from_table) = match symbol_table.lookup_by_fqsn(&sym_name) {
Some(Symbol { spec: SymbolSpec::RecordConstructor { members, type_name, index }, .. }) => (type_name.clone(), index, members),
_ => return Expr::ReductionError("Not a record constructor".to_string()),
};
diff --git a/schala-lang/language/src/symbol_table.rs b/schala-lang/language/src/symbol_table.rs
index 2095792..c82c5f1 100644
--- a/schala-lang/language/src/symbol_table.rs
+++ b/schala-lang/language/src/symbol_table.rs
@@ -26,8 +26,8 @@ impl fmt::Display for FullyQualifiedSymbolName {
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ScopeSegment {
- name: Rc, //TODO maybe this could be a &str, for efficiency?
- kind: ScopeSegmentKind,
+ pub name: Rc, //TODO maybe this could be a &str, for efficiency?
+ pub kind: ScopeSegmentKind,
}
impl fmt::Display for ScopeSegment {
diff --git a/schala-lang/language/src/typechecking.rs b/schala-lang/language/src/typechecking.rs
index 435f19d..88b8fa4 100644
--- a/schala-lang/language/src/typechecking.rs
+++ b/schala-lang/language/src/typechecking.rs
@@ -412,10 +412,12 @@ impl<'a> TypeContext<'a> {
Ok(output)
}
- fn handle_value(&mut self, val: &Rc) -> InferResult {
- match self.variable_map.lookup(val) {
+ fn handle_value(&mut self, val: &QualifiedName) -> InferResult {
+ let QualifiedName(vec) = val;
+ let var = &vec[0];
+ match self.variable_map.lookup(var) {
Some(ty) => Ok(ty.clone()),
- None => TypeError::new(format!("Couldn't find variable: {}", val))
+ None => TypeError::new(format!("Couldn't find variable: {}", &var)),
}
}