calling functions in other source files
This commit is contained in:
parent
05d241b97a
commit
f563a8048a
12 changed files with 101 additions and 77 deletions
|
|
@ -1,2 +1,2 @@
|
|||
fn get_all() -> list:
|
||||
db::get_all()
|
||||
fn get_all() -> string:
|
||||
db::get_all()
|
||||
|
|
@ -1,9 +1,2 @@
|
|||
fn get() -> list:
|
||||
service::get_all()
|
||||
|
||||
fn post(customer: Customer):
|
||||
service.add(customer)
|
||||
|
||||
|
||||
fn put(customer: Customer):
|
||||
service.update(customer)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ impl Signature {
|
|||
}
|
||||
|
||||
pub(crate) fn has_varargs(&self) -> bool {
|
||||
self.parameters.last().unwrap().name.lexeme == "varargs"
|
||||
!self.parameters.is_empty() && self.parameters.last().unwrap().name.lexeme == "varargs"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use crate::value::Value;
|
|||
use crate::{AsmRegistry, SymbolTable};
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use crate::compiler::namespace::Namespace;
|
||||
|
||||
pub fn compile(
|
||||
qualified_name: Option<&str>,
|
||||
|
|
@ -30,7 +31,7 @@ pub fn compile_function(
|
|||
function: &Function,
|
||||
symbols: &SymbolTable,
|
||||
registry: &mut AsmRegistry,
|
||||
namespace: &str,
|
||||
namespace: &Namespace,
|
||||
) -> Result<AsmChunk, CompilerErrorAtLine> {
|
||||
let fn_name = &function.name.lexeme;
|
||||
let mut compiler = AsmPass::new(fn_name);
|
||||
|
|
@ -53,7 +54,7 @@ pub fn compile_in_namespace(
|
|||
) -> Result<(), CompilerErrorAtLine> {
|
||||
let name = namespace.unwrap_or("main");
|
||||
let mut compiler = AsmPass::new(name);
|
||||
let chunk = compiler.compile(ast, symbols, registry, name)?;
|
||||
let chunk = compiler.compile(ast, symbols, registry, &Namespace::new(name))?;
|
||||
registry.insert(name.to_string(), chunk);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -136,7 +137,7 @@ impl AsmPass {
|
|||
ast: &Vec<Statement>,
|
||||
symbols: &SymbolTable,
|
||||
registry: &mut AsmRegistry,
|
||||
namespace: &str,
|
||||
namespace: &Namespace,
|
||||
) -> Result<AsmChunk, CompilerErrorAtLine> {
|
||||
self.compile_statements(ast, symbols, registry, namespace)?;
|
||||
self.emit(Return);
|
||||
|
|
@ -151,7 +152,7 @@ impl AsmPass {
|
|||
ast: &Vec<Statement>,
|
||||
symbols: &SymbolTable,
|
||||
registry: &mut AsmRegistry,
|
||||
namespace: &str,
|
||||
namespace: &Namespace,
|
||||
) -> Result<(), CompilerErrorAtLine> {
|
||||
for statement in ast {
|
||||
self.compile_statement(statement, symbols, registry, namespace)?;
|
||||
|
|
@ -165,7 +166,7 @@ impl AsmPass {
|
|||
statement: &Statement,
|
||||
symbols: &SymbolTable,
|
||||
registry: &mut AsmRegistry,
|
||||
namespace: &str,
|
||||
namespace: &Namespace,
|
||||
) -> Result<(), CompilerErrorAtLine> {
|
||||
self.current_line = statement.line();
|
||||
match statement {
|
||||
|
|
@ -193,7 +194,7 @@ impl AsmPass {
|
|||
|
||||
fn compile_expression(
|
||||
&mut self,
|
||||
namespace: &str,
|
||||
namespace: &Namespace,
|
||||
expression: &Expression,
|
||||
symbols: &SymbolTable,
|
||||
registry: &mut AsmRegistry,
|
||||
|
|
@ -258,8 +259,8 @@ impl AsmPass {
|
|||
Expression::FunctionCall {
|
||||
name, arguments, ..
|
||||
} => {
|
||||
let qname = format!("{}/{}", namespace, name);
|
||||
let function = symbols.get(&qname).or(symbols.get(name));
|
||||
let qname = format!("{}/{}", namespace.pop(), name.replace("::","/"));
|
||||
let function = symbols.get(&qname);
|
||||
match function {
|
||||
Some(Symbol::Function { parameters, .. }) => {
|
||||
let name_index = self.chunk.find_constant(&qname).unwrap_or_else(|| {
|
||||
|
|
@ -496,7 +497,7 @@ impl AsmPass {
|
|||
// named parameters do not have to be passed in order, but they do need to be evaluated in the order of the called function/constructor
|
||||
fn get_arguments_in_order(
|
||||
&mut self,
|
||||
namespace: &str,
|
||||
namespace: &Namespace,
|
||||
symbols: &SymbolTable,
|
||||
registry: &mut AsmRegistry,
|
||||
arguments: &[Expression],
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
use crate::builtins::globals::GLOBAL_FUNCTIONS;
|
||||
use crate::compiler::ast_pass::Expression::{
|
||||
Assignment, FieldGet, FunctionCall, IfElseExpression, IfExpression, LetExpression, ListGet,
|
||||
MapGet, MethodCall, NamedParameter, Stop, Variable,
|
||||
};
|
||||
use crate::compiler::tokens::TokenType::{
|
||||
Bang, Bool, Char, Colon, DateTime, Dot, Else, Eof, Eol, Equal, False, FloatingPoint, Fn, For,
|
||||
Greater, GreaterEqual, GreaterGreater, Identifier, If, In, Indent, Integer, LeftBrace,
|
||||
|
|
@ -151,7 +147,7 @@ impl AstCompiler {
|
|||
Err(self.error_at_line(Expected("-> or ?")))
|
||||
};
|
||||
}
|
||||
Ok(Stop {
|
||||
Ok(Expression::Stop {
|
||||
line: self.peek().line,
|
||||
})
|
||||
}
|
||||
|
|
@ -162,7 +158,7 @@ impl AstCompiler {
|
|||
self.consume(&RightBrace, Expected("'}' after guard expression."))?;
|
||||
Ok(query_params)
|
||||
} else {
|
||||
Ok(Stop {
|
||||
Ok(Expression::Stop {
|
||||
line: self.peek().line,
|
||||
})
|
||||
}
|
||||
|
|
@ -174,7 +170,7 @@ impl AstCompiler {
|
|||
self.consume(&RightBrace, Expected("'}' after guard expression."))?;
|
||||
Ok(path_params)
|
||||
} else {
|
||||
Ok(Stop {
|
||||
Ok(Expression::Stop {
|
||||
line: self.peek().line,
|
||||
})
|
||||
}
|
||||
|
|
@ -347,7 +343,7 @@ impl AstCompiler {
|
|||
},
|
||||
);
|
||||
|
||||
Ok(LetExpression {
|
||||
Ok(Expression::LetExpression {
|
||||
name: name_token,
|
||||
var_type,
|
||||
initializer: Box::new(initializer),
|
||||
|
|
@ -391,8 +387,8 @@ impl AstCompiler {
|
|||
if self.match_token(&[Equal]) {
|
||||
let operator = self.previous().clone();
|
||||
let right = self.comparison(symbol_table)?;
|
||||
if let Variable { name, .. } = expr {
|
||||
Ok(Assignment {
|
||||
if let Expression::Variable { name, .. } = expr {
|
||||
Ok(Expression::Assignment {
|
||||
line: operator.line,
|
||||
variable_name: name.to_string(),
|
||||
value: Box::new(right),
|
||||
|
|
@ -499,13 +495,13 @@ impl AstCompiler {
|
|||
|
||||
self.inc_indent();
|
||||
|
||||
Ok(IfElseExpression {
|
||||
Ok(Expression::IfElseExpression {
|
||||
condition: Box::new(condition),
|
||||
then_branch,
|
||||
else_branch: self.compile(symbol_table)?,
|
||||
})
|
||||
} else {
|
||||
Ok(IfExpression {
|
||||
Ok(Expression::IfExpression {
|
||||
condition: Box::new(condition),
|
||||
then_branch,
|
||||
})
|
||||
|
|
@ -534,22 +530,23 @@ impl AstCompiler {
|
|||
}
|
||||
}
|
||||
|
||||
// index into list
|
||||
fn index(&mut self, operand: Expression, index: Expression) -> Expr {
|
||||
let get = match &operand {
|
||||
Expression::Map { .. } => MapGet {
|
||||
Expression::Map { .. } => Expression::MapGet {
|
||||
map: Box::new(operand),
|
||||
key: Box::new(index),
|
||||
},
|
||||
Expression::List { .. } => ListGet {
|
||||
Expression::List { .. } => Expression::ListGet {
|
||||
list: Box::new(operand),
|
||||
index: Box::new(index),
|
||||
},
|
||||
Variable { var_type, .. } => match var_type {
|
||||
ListType => ListGet {
|
||||
Expression::Variable { var_type, .. } => match var_type {
|
||||
ListType => Expression::ListGet {
|
||||
list: Box::new(operand),
|
||||
index: Box::new(index),
|
||||
},
|
||||
MapType => MapGet {
|
||||
MapType => Expression::MapGet {
|
||||
map: Box::new(operand),
|
||||
key: Box::new(index),
|
||||
},
|
||||
|
|
@ -578,7 +575,7 @@ impl AstCompiler {
|
|||
) -> Expr {
|
||||
if self.match_token(&[LeftParen]) {
|
||||
let arguments = self.arguments(symbol_table)?;
|
||||
Ok(MethodCall {
|
||||
Ok(Expression::MethodCall {
|
||||
receiver: Box::new(receiver.clone()),
|
||||
method_name: op.lexeme,
|
||||
arguments,
|
||||
|
|
@ -586,7 +583,7 @@ impl AstCompiler {
|
|||
})
|
||||
} else {
|
||||
// no test yet
|
||||
Ok(FieldGet {
|
||||
Ok(Expression::FieldGet {
|
||||
receiver: Box::new(receiver.clone()),
|
||||
field: op.lexeme.clone(),
|
||||
})
|
||||
|
|
@ -698,7 +695,7 @@ impl AstCompiler {
|
|||
fn named_parameter(&mut self, name: &Token, symbol_table: &mut SymbolTable) -> Expr {
|
||||
let value = self.expression(symbol_table)?;
|
||||
let line = name.line;
|
||||
Ok(NamedParameter {
|
||||
Ok(Expression::NamedParameter {
|
||||
name: name.clone(),
|
||||
value: Box::new(value),
|
||||
line,
|
||||
|
|
@ -751,7 +748,7 @@ impl AstCompiler {
|
|||
} else {
|
||||
&Unknown
|
||||
};
|
||||
Ok(Variable {
|
||||
Ok(Expression::Variable {
|
||||
name: name.lexeme.to_string(),
|
||||
var_type: var_type.clone(),
|
||||
line: name.line,
|
||||
|
|
@ -760,7 +757,7 @@ impl AstCompiler {
|
|||
|
||||
fn function_call(&mut self, name: Token, symbol_table: &mut SymbolTable) -> Expr {
|
||||
let arguments = self.arguments(symbol_table)?;
|
||||
Ok(FunctionCall {
|
||||
Ok(Expression::FunctionCall {
|
||||
line: self.peek().line,
|
||||
name: name.lexeme.to_string(),
|
||||
arguments,
|
||||
|
|
@ -1020,19 +1017,19 @@ impl Expression {
|
|||
Self::Range { line, .. } => *line,
|
||||
Self::List { line, .. } => *line,
|
||||
Self::Map { line, .. } => *line,
|
||||
Variable { line, .. } => *line,
|
||||
Assignment { line, .. } => *line,
|
||||
FunctionCall { line, .. } => *line,
|
||||
MethodCall { line, .. } => *line,
|
||||
Stop { line } => *line,
|
||||
NamedParameter { line, .. } => *line,
|
||||
MapGet { .. } => 0,
|
||||
ListGet { .. } => 0,
|
||||
FieldGet { .. } => 0,
|
||||
IfExpression { condition, .. } => condition.line(),
|
||||
IfElseExpression { condition, .. } => condition.line(),
|
||||
LetExpression { name, .. } => name.line,
|
||||
Expression::ForStatement { loop_var, .. } => loop_var.line,
|
||||
Self::Variable { line, .. } => *line,
|
||||
Self::Assignment { line, .. } => *line,
|
||||
Self::FunctionCall { line, .. } => *line,
|
||||
Self::MethodCall { line, .. } => *line,
|
||||
Self::Stop { line } => *line,
|
||||
Self::NamedParameter { line, .. } => *line,
|
||||
Self::MapGet { .. } => 0,
|
||||
Self::ListGet { .. } => 0,
|
||||
Self::FieldGet { .. } => 0,
|
||||
Self::IfExpression { condition, .. } => condition.line(),
|
||||
Self::IfElseExpression { condition, .. } => condition.line(),
|
||||
Self::LetExpression { name, .. } => name.line,
|
||||
Self::ForStatement { loop_var, .. } => loop_var.line,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
mod tests {
|
||||
use crate::DATE_FORMAT_TIMEZONE;
|
||||
use crate::compiler::{compile, run};
|
||||
use crate::errors::CompilerError::{IllegalArgumentsException, ReservedFunctionName};
|
||||
use crate::errors::CompilerError::{IllegalArgumentsException, ReservedFunctionName, UndeclaredVariable};
|
||||
use crate::errors::CompilerErrorAtLine;
|
||||
use crate::errors::RuntimeError::{IllegalArgumentException, IndexOutOfBounds, NotSortable};
|
||||
use crate::errors::TipiLangError::{Compiler, Runtime};
|
||||
|
|
@ -474,20 +474,21 @@ else:
|
|||
a"#)
|
||||
.unwrap();
|
||||
}
|
||||
// #[test]
|
||||
// fn package() {
|
||||
// assert_eq!(run(r#"a::b.c()"#), Ok(Value::U32(48)));
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn guards() {
|
||||
assert_eq!(
|
||||
run(r#"fn get_all_users() -> list:
|
||||
| /{uuid} -> service.get_by_uuid(uuid)?"#),
|
||||
Ok(Value::Void)
|
||||
);
|
||||
fn package() {
|
||||
assert_eq!(run(r#"a::b.c()"#), Err(Compiler(CompilerErrorAtLine {error: UndeclaredVariable("a::b".to_string()), line: 1 })));
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn guards() {
|
||||
// assert_eq!(
|
||||
// run(r#"fn get_all_users() -> list:
|
||||
// | /{uuid} -> service.get_by_uuid(uuid)?"#),
|
||||
// Ok(Value::Void)
|
||||
// );
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn query() {
|
||||
let result =
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@ pub mod scan_pass;
|
|||
pub mod ast_pass;
|
||||
pub mod tokens;
|
||||
pub mod assembly_pass;
|
||||
pub(crate) mod namespace;
|
||||
|
||||
pub fn compile_sourcedir(source_dir: &str) -> Result<HashMap<String, AsmChunk>, TipiLangError> {
|
||||
let mut asm_registry = AsmRegistry::new();
|
||||
let mut symbol_table = HashMap::new();
|
||||
|
||||
for entry in WalkDir::new(source_dir).into_iter().filter_map(|e| e.ok()) {
|
||||
let path = entry.path().to_str().unwrap();
|
||||
|
|
@ -21,7 +23,6 @@ pub fn compile_sourcedir(source_dir: &str) -> Result<HashMap<String, AsmChunk>,
|
|||
println!("-- Compiling {} -- ", path);
|
||||
let source = fs::read_to_string(path).map_err(map_underlying())?;
|
||||
let tokens = scan_pass::scan(&source)?;
|
||||
let mut symbol_table = HashMap::new();
|
||||
match ast_pass::compile(Some(path), tokens, &mut symbol_table) {
|
||||
Ok(statements) => {
|
||||
let path = path.strip_prefix(source_dir).unwrap().replace(TIPI_EXT, "");
|
||||
|
|
|
|||
27
src/compiler/namespace.rs
Normal file
27
src/compiler/namespace.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
pub(crate) struct Namespace {
|
||||
elements: Vec<String>,
|
||||
}
|
||||
|
||||
impl Namespace {
|
||||
pub(crate) fn new(path: &str) -> Self {
|
||||
Self {
|
||||
elements: path.split('/').map(|path| path.to_string()).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn pop(&self) -> Self{
|
||||
let mut copy = self.elements.to_vec();
|
||||
copy.pop();
|
||||
Self{
|
||||
elements: copy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Namespace {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.elements.join("/"))
|
||||
}
|
||||
}
|
||||
|
|
@ -88,12 +88,9 @@ impl Scanner {
|
|||
'#' => self.add_token(TokenType::Hash),
|
||||
'+' => self.add_token(TokenType::Plus),
|
||||
':' => {
|
||||
let t = if self.match_next(':') {
|
||||
TokenType::ColonColon
|
||||
} else {
|
||||
TokenType::Colon
|
||||
};
|
||||
self.add_token(t);
|
||||
if !self.match_next(':') {
|
||||
self.add_token(TokenType::Colon);
|
||||
}
|
||||
}
|
||||
';' => println!("Warning: Ignoring semicolon at line {}", self.line),
|
||||
'*' => self.add_token(TokenType::Star),
|
||||
|
|
@ -189,7 +186,13 @@ impl Scanner {
|
|||
}
|
||||
|
||||
fn identifier(&mut self) {
|
||||
while is_alphanumeric(self.peek()) {
|
||||
while is_alphanumeric(self.peek())
|
||||
|| self.peek() == '_'
|
||||
|| (self.peek() == ':' && self.peek_next() == ':')
|
||||
{
|
||||
if self.peek() == ':' && self.peek_next() == ':' {
|
||||
self.advance();
|
||||
}
|
||||
self.advance();
|
||||
}
|
||||
let value: String = self.chars[self.start..self.current].iter().collect();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use std::io;
|
|||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use crate::compiler::namespace::Namespace;
|
||||
|
||||
pub fn start(registry: Arc<ArcSwap<HashMap<String, AsmChunk>>>) -> Result<(), TipiLangError> {
|
||||
println!("REPL started -- Type ctrl-c to exit (both the repl and the server)");
|
||||
|
|
@ -44,7 +45,7 @@ pub fn start(registry: Arc<ArcSwap<HashMap<String, AsmChunk>>>) -> Result<(), Ti
|
|||
};
|
||||
symbol_builder::build("", &ast, &mut symbol_table);
|
||||
|
||||
match asm_pass.compile(&ast, &symbol_table, &mut registry_copy, "") {
|
||||
match asm_pass.compile(&ast, &symbol_table, &mut registry_copy, &Namespace::new("")) {
|
||||
Ok(chunk) => {
|
||||
registry_copy.insert("main".to_string(), chunk);
|
||||
registry.store(Arc::new(registry_copy));
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ fn make_qname(path: &str, name: &Token) -> String {
|
|||
if path.is_empty() {
|
||||
name.lexeme.to_string()
|
||||
} else {
|
||||
format!("{}.{}", path, name.lexeme)
|
||||
format!("{}/{}", path, name.lexeme)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"languages": [{
|
||||
"id": "tipi",
|
||||
"aliases": ["tipi-lang", "tipi"],
|
||||
"extensions": [".tipi"],
|
||||
"extensions": [".tp"],
|
||||
"configuration": "./language-configuration.json"
|
||||
}],
|
||||
"grammars": [{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue