Much work on adding and calling.
This commit is contained in:
parent
81ceeeadb8
commit
e1afb6b43b
@ -6,8 +6,10 @@ pub enum AsmInstruction {
|
||||
Move(Move),
|
||||
Push(Push),
|
||||
Pop(Pop),
|
||||
InvokeStatic(InvokeStatic),
|
||||
InvokePlatformStatic(InvokePlatformStatic),
|
||||
LoadConstant(LoadConstant),
|
||||
Add(Add),
|
||||
}
|
||||
|
||||
impl AsmInstruction {
|
||||
@ -16,10 +18,12 @@ impl AsmInstruction {
|
||||
AsmInstruction::Move(asm_move) => asm_move.dvm(),
|
||||
AsmInstruction::Push(push) => push.dvm(),
|
||||
AsmInstruction::Pop(pop) => pop.dvm(),
|
||||
AsmInstruction::InvokeStatic(invoke_static) => invoke_static.dvm(),
|
||||
AsmInstruction::InvokePlatformStatic(invoke_platform_static) => {
|
||||
invoke_platform_static.dvm()
|
||||
}
|
||||
AsmInstruction::LoadConstant(load_constant) => load_constant.dvm(),
|
||||
AsmInstruction::Add(add) => add.dvm(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -100,6 +104,21 @@ impl Pop {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InvokeStatic {
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl InvokeStatic {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Self { name: name.into() }
|
||||
}
|
||||
|
||||
pub fn dvm(&self) -> Instruction {
|
||||
Instruction::InvokeStatic(Rc::from(self.name.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InvokePlatformStatic {
|
||||
name: String,
|
||||
@ -137,3 +156,24 @@ impl LoadConstant {
|
||||
Instruction::LoadStringConstant(Rc::from(self.name.clone()), self.destination_register)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Add {
|
||||
IntInt(usize, usize, usize),
|
||||
StringString(usize, usize, usize),
|
||||
StringInt(usize, usize, usize),
|
||||
}
|
||||
|
||||
impl Add {
|
||||
pub fn dvm(&self) -> Instruction {
|
||||
match self {
|
||||
Add::IntInt(lhs, rhs, destination) => Instruction::AddIntInt(*lhs, *rhs, *destination),
|
||||
Add::StringString(lhs, rhs, destination) => {
|
||||
Instruction::AddStringString(*lhs, *rhs, *destination)
|
||||
}
|
||||
Add::StringInt(lhs, rhs, destination) => {
|
||||
Instruction::AddStringInt(*lhs, *rhs, *destination)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
173
dmc-lib/src/ast/additive_expression.rs
Normal file
173
dmc-lib/src/ast/additive_expression.rs
Normal file
@ -0,0 +1,173 @@
|
||||
use crate::asm::asm_instruction::{Add, AsmInstruction, LoadConstant, Move, Operand, Pop};
|
||||
use crate::ast::assemble_context::AssembleContext;
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::constants_table::ConstantsTable;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::ExpressibleSymbol;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::type_info::TypeInfo;
|
||||
|
||||
pub struct AdditiveExpression {
|
||||
lhs: Box<Expression>,
|
||||
rhs: Box<Expression>,
|
||||
source_range: SourceRange,
|
||||
}
|
||||
|
||||
impl AdditiveExpression {
|
||||
pub fn new(lhs: Expression, rhs: Expression, source_range: SourceRange) -> Self {
|
||||
Self {
|
||||
lhs: lhs.into(),
|
||||
rhs: rhs.into(),
|
||||
source_range,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics = vec![];
|
||||
diagnostics.append(&mut self.lhs.gather_declared_names(symbol_table));
|
||||
diagnostics.append(&mut self.rhs.gather_declared_names(symbol_table));
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics = vec![];
|
||||
diagnostics.append(&mut self.lhs.check_name_usages(symbol_table));
|
||||
diagnostics.append(&mut self.rhs.check_name_usages(symbol_table));
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
self.lhs.type_check(symbol_table);
|
||||
self.rhs.type_check(symbol_table);
|
||||
|
||||
let lhs_type_info = self.lhs.type_info();
|
||||
let rhs_type_info = self.rhs.type_info();
|
||||
if lhs_type_info.can_add(&rhs_type_info) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vec![Diagnostic::new(
|
||||
&format!("Cannot add {} to {}", lhs_type_info, rhs_type_info),
|
||||
self.source_range.start(),
|
||||
self.source_range.end(),
|
||||
)])
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_side(
|
||||
expression: &Expression,
|
||||
context: &mut AssembleContext,
|
||||
symbol_table: &SymbolTable,
|
||||
constants_table: &mut ConstantsTable,
|
||||
) -> usize {
|
||||
match expression {
|
||||
Expression::Call(call) => {
|
||||
call.assemble(context, symbol_table, constants_table);
|
||||
let register = context.new_local_register();
|
||||
context.instruction(AsmInstruction::Pop(Pop::new(register)));
|
||||
register
|
||||
}
|
||||
Expression::IntegerLiteral(integer_literal) => {
|
||||
let register = context.new_local_register();
|
||||
context.instruction(AsmInstruction::Move(Move::new(
|
||||
Operand::IntegerLiteral(integer_literal.value()),
|
||||
register,
|
||||
)));
|
||||
register
|
||||
}
|
||||
Expression::String(string_literal) => {
|
||||
let register = context.new_local_register();
|
||||
let constant_name = constants_table.insert_string(string_literal.content());
|
||||
context.instruction(AsmInstruction::LoadConstant(LoadConstant::new(
|
||||
&constant_name,
|
||||
register,
|
||||
)));
|
||||
register
|
||||
}
|
||||
Expression::Identifier(identifier) => {
|
||||
let register = context.new_local_register();
|
||||
match identifier.expressible_symbol() {
|
||||
ExpressibleSymbol::Function(_) => unreachable!(),
|
||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
||||
let offset = parameter_symbol.borrow().stack_frame_offset();
|
||||
context.instruction(AsmInstruction::Move(Move::new(
|
||||
Operand::StackFrameOffset(offset),
|
||||
register,
|
||||
)));
|
||||
}
|
||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
||||
context.instruction(AsmInstruction::Move(Move::new(
|
||||
Operand::Register(variable_symbol.borrow().register()),
|
||||
register,
|
||||
)));
|
||||
}
|
||||
}
|
||||
register
|
||||
}
|
||||
Expression::Additive(additive_expression) => {
|
||||
additive_expression.assemble(context, symbol_table, constants_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assemble(
|
||||
&self,
|
||||
context: &mut AssembleContext,
|
||||
symbol_table: &SymbolTable,
|
||||
constants_table: &mut ConstantsTable,
|
||||
) -> usize {
|
||||
let lhs_register = Self::assemble_side(&self.lhs, context, symbol_table, constants_table);
|
||||
let rhs_register = Self::assemble_side(&self.rhs, context, symbol_table, constants_table);
|
||||
let result_register = context.new_local_register();
|
||||
match self.lhs.type_info() {
|
||||
TypeInfo::Integer => match self.rhs.type_info() {
|
||||
TypeInfo::Integer => {
|
||||
context.instruction(AsmInstruction::Add(Add::IntInt(
|
||||
lhs_register,
|
||||
rhs_register,
|
||||
result_register,
|
||||
)));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
TypeInfo::String => match self.rhs.type_info() {
|
||||
TypeInfo::Integer => {
|
||||
context.instruction(AsmInstruction::Add(Add::StringInt(
|
||||
lhs_register,
|
||||
rhs_register,
|
||||
result_register,
|
||||
)));
|
||||
}
|
||||
TypeInfo::String => {
|
||||
context.instruction(AsmInstruction::Add(Add::StringString(
|
||||
lhs_register,
|
||||
rhs_register,
|
||||
result_register,
|
||||
)));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
result_register
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> TypeInfo {
|
||||
self.lhs.type_info().additive_result(&self.rhs.type_info())
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
&self.source_range
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::asm::asm_instruction::{
|
||||
AsmInstruction, InvokePlatformStatic, LoadConstant, Operand, Push,
|
||||
AsmInstruction, InvokePlatformStatic, InvokeStatic, LoadConstant, Operand, Push,
|
||||
};
|
||||
use crate::ast::assemble_context::AssembleContext;
|
||||
use crate::ast::expression::Expression;
|
||||
@ -166,6 +166,13 @@ impl Call {
|
||||
))))
|
||||
}
|
||||
},
|
||||
Expression::Additive(additive_expression) => {
|
||||
let result_register =
|
||||
additive_expression.assemble(context, symbol_table, constants_table);
|
||||
context.instruction(AsmInstruction::Push(Push::new(Operand::Register(
|
||||
result_register,
|
||||
))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +194,9 @@ impl Call {
|
||||
InvokePlatformStatic::new(function_symbol.name(), arg_count),
|
||||
));
|
||||
} else {
|
||||
todo!("non-platform invoke")
|
||||
context.instruction(AsmInstruction::InvokeStatic(InvokeStatic::new(
|
||||
function_symbol.name(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use crate::ast::additive_expression::AdditiveExpression;
|
||||
use crate::ast::call::Call;
|
||||
use crate::ast::identifier::Identifier;
|
||||
use crate::ast::integer_literal::IntegerLiteral;
|
||||
@ -12,6 +13,7 @@ pub enum Expression {
|
||||
IntegerLiteral(IntegerLiteral),
|
||||
String(StringLiteral),
|
||||
Identifier(Identifier),
|
||||
Additive(AdditiveExpression),
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
@ -19,6 +21,14 @@ impl Expression {
|
||||
match self {
|
||||
Expression::Call(call) => call.gather_declared_names(symbol_table),
|
||||
Expression::Identifier(identifier) => identifier.gather_declared_names(symbol_table),
|
||||
Expression::Additive(additive_expression) => {
|
||||
match additive_expression.gather_declared_names(symbol_table) {
|
||||
Ok(_) => {
|
||||
vec![]
|
||||
}
|
||||
Err(diagnostics) => diagnostics,
|
||||
}
|
||||
}
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
@ -27,6 +37,14 @@ impl Expression {
|
||||
match self {
|
||||
Expression::Call(call) => call.check_name_usages(symbol_table),
|
||||
Expression::Identifier(identifier) => identifier.check_name_usages(symbol_table),
|
||||
Expression::Additive(additive_expression) => {
|
||||
match additive_expression.check_name_usages(symbol_table) {
|
||||
Ok(_) => {
|
||||
vec![]
|
||||
}
|
||||
Err(diagnostics) => diagnostics,
|
||||
}
|
||||
}
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
@ -34,6 +52,14 @@ impl Expression {
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
match self {
|
||||
Expression::Call(call) => call.type_check(symbol_table),
|
||||
Expression::Additive(additive_expression) => {
|
||||
match additive_expression.type_check(symbol_table) {
|
||||
Ok(_) => {
|
||||
vec![]
|
||||
}
|
||||
Err(diagnostics) => diagnostics,
|
||||
}
|
||||
}
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
@ -44,6 +70,7 @@ impl Expression {
|
||||
Expression::IntegerLiteral(_) => TypeInfo::Integer,
|
||||
Expression::String(_) => TypeInfo::String,
|
||||
Expression::Identifier(identifier) => identifier.type_info(),
|
||||
Expression::Additive(additive_expression) => additive_expression.type_info(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,6 +80,7 @@ impl Expression {
|
||||
Expression::IntegerLiteral(integer_literal) => integer_literal.source_range(),
|
||||
Expression::String(string_literal) => string_literal.source_range(),
|
||||
Expression::Identifier(identifier) => identifier.source_range(),
|
||||
Expression::Additive(additive_expression) => additive_expression.source_range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,9 @@ impl ExpressionStatement {
|
||||
Expression::Call(call) => {
|
||||
call.assemble(context, symbol_table, constants_table);
|
||||
}
|
||||
Expression::Additive(additive) => {
|
||||
additive.assemble(context, symbol_table, constants_table);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::ast::parameter::Parameter;
|
||||
use crate::ast::type_use::TypeUse;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::FunctionSymbol;
|
||||
@ -8,6 +9,7 @@ pub struct ExternFunction {
|
||||
declared_name: String,
|
||||
declared_name_source_range: SourceRange,
|
||||
parameters: Vec<Parameter>,
|
||||
return_type: TypeUse,
|
||||
}
|
||||
|
||||
impl ExternFunction {
|
||||
@ -15,11 +17,13 @@ impl ExternFunction {
|
||||
name: &str,
|
||||
declared_name_source_range: SourceRange,
|
||||
parameters: Vec<Parameter>,
|
||||
return_type: TypeUse,
|
||||
) -> ExternFunction {
|
||||
ExternFunction {
|
||||
declared_name: name.into(),
|
||||
declared_name_source_range,
|
||||
parameters,
|
||||
return_type,
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,8 +34,11 @@ impl ExternFunction {
|
||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
let insert_result =
|
||||
symbol_table.insert_function_symbol(FunctionSymbol::new(&self.declared_name, true));
|
||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
&self.declared_name,
|
||||
true,
|
||||
self.return_type.to_type_info(),
|
||||
));
|
||||
|
||||
let function_symbol = match insert_result {
|
||||
Ok(function_symbol) => function_symbol,
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
use crate::ast::assemble_context::AssembleContext;
|
||||
use crate::ast::parameter::Parameter;
|
||||
use crate::ast::statement::Statement;
|
||||
use crate::ast::type_use::TypeUse;
|
||||
use crate::constants_table::ConstantsTable;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::FunctionSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use crate::type_info::TypeInfo;
|
||||
use std::ops::Neg;
|
||||
|
||||
pub struct Function {
|
||||
declared_name: String,
|
||||
declared_name_source_range: SourceRange,
|
||||
parameters: Vec<Parameter>,
|
||||
return_type: Option<TypeUse>,
|
||||
statements: Vec<Statement>,
|
||||
}
|
||||
|
||||
@ -19,12 +23,14 @@ impl Function {
|
||||
declared_name: &str,
|
||||
declared_name_source_range: SourceRange,
|
||||
parameters: Vec<Parameter>,
|
||||
return_type: Option<TypeUse>,
|
||||
statements: Vec<Statement>,
|
||||
) -> Self {
|
||||
Self {
|
||||
declared_name: declared_name.to_string(),
|
||||
declared_name_source_range,
|
||||
parameters,
|
||||
return_type,
|
||||
statements,
|
||||
}
|
||||
}
|
||||
@ -41,8 +47,14 @@ impl Function {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
// insert function symbol
|
||||
let insert_result =
|
||||
symbol_table.insert_function_symbol(FunctionSymbol::new(self.declared_name(), false));
|
||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
self.declared_name(),
|
||||
false,
|
||||
self.return_type
|
||||
.as_ref()
|
||||
.map(|return_type| return_type.to_type_info())
|
||||
.unwrap_or(TypeInfo::Void),
|
||||
));
|
||||
|
||||
// get function symbol if successful
|
||||
let function_symbol = match insert_result {
|
||||
@ -67,9 +79,14 @@ impl Function {
|
||||
// handle parameters
|
||||
symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name));
|
||||
let mut parameter_symbols = vec![];
|
||||
for parameter in &mut self.parameters {
|
||||
let parameter_count = self.parameters.len();
|
||||
let stack_frame_offset_base = (parameter_count as isize).neg();
|
||||
for (i, parameter) in self.parameters.iter_mut().enumerate() {
|
||||
match parameter.gather_declared_names(symbol_table) {
|
||||
Ok(parameter_symbol) => {
|
||||
parameter_symbol
|
||||
.borrow_mut()
|
||||
.set_stack_frame_offset(stack_frame_offset_base + (i as isize));
|
||||
parameter_symbols.push(parameter_symbol);
|
||||
}
|
||||
Err(mut parameter_diagnostics) => {
|
||||
@ -144,6 +161,7 @@ impl Function {
|
||||
for statement in &self.statements {
|
||||
statement.assemble(context, symbol_table, constants_table);
|
||||
}
|
||||
// todo: function exit, including popping passed args and pushing return value
|
||||
context.complete_function();
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,6 +130,13 @@ impl LetStatement {
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::Additive(additive) => {
|
||||
let result_register = additive.assemble(context, symbol_table, constants_table);
|
||||
context.instruction(AsmInstruction::Move(Move::new(
|
||||
Operand::Register(result_register),
|
||||
destination_register,
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
pub mod additive_expression;
|
||||
pub mod assemble_context;
|
||||
pub mod call;
|
||||
pub mod compilation_unit;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::type_info::TypeInfo;
|
||||
|
||||
pub struct TypeUse {
|
||||
declared_name: String,
|
||||
@ -16,4 +17,8 @@ impl TypeUse {
|
||||
pub fn declared_name(&self) -> &str {
|
||||
&self.declared_name
|
||||
}
|
||||
|
||||
pub fn to_type_info(&self) -> TypeInfo {
|
||||
TypeInfo::from_declared_name(self.declared_name())
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,9 @@ impl<'a> Lexer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let token = if chunk.starts_with("(") {
|
||||
let token = if chunk.starts_with("->") {
|
||||
Token::new(self.position, self.position + 2, TokenKind::RightArrow)
|
||||
} else if chunk.starts_with("(") {
|
||||
Token::new(self.position, self.position + 1, TokenKind::LeftParentheses)
|
||||
} else if chunk.starts_with(")") {
|
||||
Token::new(
|
||||
@ -42,6 +44,8 @@ impl<'a> Lexer<'a> {
|
||||
self.position + 1,
|
||||
TokenKind::RightParentheses,
|
||||
)
|
||||
} else if chunk.starts_with("+") {
|
||||
Token::new(self.position, self.position + 1, TokenKind::Plus)
|
||||
} else if chunk.starts_with("=") {
|
||||
Token::new(self.position, self.position + 1, TokenKind::Equals)
|
||||
} else if chunk.starts_with(",") {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use crate::ast::additive_expression::AdditiveExpression;
|
||||
use crate::ast::call::Call;
|
||||
use crate::ast::compilation_unit::CompilationUnit;
|
||||
use crate::ast::expression::Expression;
|
||||
@ -218,13 +219,26 @@ impl<'a> Parser<'a> {
|
||||
fn function(&mut self) -> Result<Function, Vec<Diagnostic>> {
|
||||
self.expect_advance(TokenKind::Fn)?;
|
||||
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
||||
|
||||
self.expect_advance(TokenKind::LeftParentheses)?;
|
||||
|
||||
let parameters = self.parameter_list()?;
|
||||
|
||||
self.expect_advance(TokenKind::RightParentheses)?;
|
||||
let mut statements = vec![];
|
||||
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
let return_type = if self.current.is_some() && self.peek_current(TokenKind::RightArrow) {
|
||||
match self.return_type() {
|
||||
Ok(type_use) => Some(type_use),
|
||||
Err(mut return_type_diagnostics) => {
|
||||
diagnostics.append(&mut return_type_diagnostics);
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut statements = vec![];
|
||||
while self.current.is_some() && !self.peek_current(TokenKind::End) {
|
||||
let statement_result = self.statement();
|
||||
match statement_result {
|
||||
@ -251,6 +265,7 @@ impl<'a> Parser<'a> {
|
||||
self.token_text(&identifier_token),
|
||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||
parameters,
|
||||
return_type,
|
||||
statements,
|
||||
))
|
||||
} else {
|
||||
@ -285,11 +300,14 @@ impl<'a> Parser<'a> {
|
||||
Ok(_) => {}
|
||||
}
|
||||
|
||||
let return_type = self.return_type()?;
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
Ok(ExternFunction::new(
|
||||
self.token_text(&identifier_token),
|
||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||
maybe_parameters.unwrap(),
|
||||
return_type,
|
||||
))
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
@ -331,6 +349,11 @@ impl<'a> Parser<'a> {
|
||||
))
|
||||
}
|
||||
|
||||
fn return_type(&mut self) -> Result<TypeUse, Vec<Diagnostic>> {
|
||||
self.expect_advance(TokenKind::RightArrow)?;
|
||||
self.type_use()
|
||||
}
|
||||
|
||||
fn type_use(&mut self) -> Result<TypeUse, Vec<Diagnostic>> {
|
||||
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
||||
Ok(TypeUse::new(
|
||||
@ -364,96 +387,102 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||
let current = self.get_current().clone(); // I don't love this clone
|
||||
let mut diagnostics = vec![];
|
||||
let mut expression = match current.kind() {
|
||||
self.additive_expression()
|
||||
}
|
||||
|
||||
fn additive_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||
let mut result = self.suffix_expression()?;
|
||||
while self.current.is_some() {
|
||||
let current = self.get_current();
|
||||
match current.kind() {
|
||||
TokenKind::Plus => {
|
||||
self.advance(); // plus
|
||||
let rhs = self.expression()?;
|
||||
let source_range =
|
||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||
result =
|
||||
Expression::Additive(AdditiveExpression::new(result, rhs, source_range));
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn suffix_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||
let mut result = self.expression_base()?;
|
||||
while self.current.is_some() {
|
||||
let current = self.get_current();
|
||||
match current.kind() {
|
||||
TokenKind::LeftParentheses => {
|
||||
result = Expression::Call(self.call(result)?);
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn expression_base(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||
let current = self.get_current();
|
||||
match current.kind() {
|
||||
TokenKind::IntegerLiteral => {
|
||||
let raw = self.token_text(¤t);
|
||||
let source_range = SourceRange::new(current.start(), current.end());
|
||||
self.advance();
|
||||
Expression::IntegerLiteral(IntegerLiteral::new(
|
||||
Ok(Expression::IntegerLiteral(IntegerLiteral::new(
|
||||
i32::from_str(raw).unwrap(),
|
||||
source_range,
|
||||
))
|
||||
)))
|
||||
}
|
||||
TokenKind::String => {
|
||||
let with_quotes = self.token_text(¤t);
|
||||
let source_range = SourceRange::new(current.start(), current.end());
|
||||
self.advance();
|
||||
Expression::String(StringLiteral::new(
|
||||
Ok(Expression::String(StringLiteral::new(
|
||||
&with_quotes[1..with_quotes.len() - 1],
|
||||
source_range,
|
||||
))
|
||||
)))
|
||||
}
|
||||
TokenKind::Identifier => {
|
||||
let declared_name = self.token_text(¤t);
|
||||
let source_range = SourceRange::new(current.start(), current.end());
|
||||
self.advance();
|
||||
Expression::Identifier(Identifier::new(declared_name, source_range))
|
||||
Ok(Expression::Identifier(Identifier::new(
|
||||
declared_name,
|
||||
source_range,
|
||||
)))
|
||||
}
|
||||
_ => {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
&format!(
|
||||
"Expected any of {:?} but found {:?}",
|
||||
[
|
||||
TokenKind::IntegerLiteral,
|
||||
TokenKind::String,
|
||||
TokenKind::Identifier
|
||||
],
|
||||
current.kind()
|
||||
),
|
||||
current.start(),
|
||||
current.end(),
|
||||
));
|
||||
|
||||
self.advance_until(&[
|
||||
TokenKind::IntegerLiteral,
|
||||
TokenKind::String,
|
||||
TokenKind::Identifier,
|
||||
]);
|
||||
if self.current.is_some() {
|
||||
let try_again_result = self.expression();
|
||||
match try_again_result {
|
||||
Ok(expression) => expression,
|
||||
Err(mut try_again_diagnostics) => {
|
||||
diagnostics.append(&mut try_again_diagnostics);
|
||||
return Err(diagnostics);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(diagnostics);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// postfixes
|
||||
while let Some(current) = &self.current {
|
||||
match current.kind() {
|
||||
TokenKind::LeftParentheses => {
|
||||
expression = Expression::Call(self.call(expression)?);
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
Ok(expression)
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, callee: Expression) -> Result<Call, Vec<Diagnostic>> {
|
||||
self.expect_advance(TokenKind::LeftParentheses)?;
|
||||
let mut arguments = vec![];
|
||||
while self.current.is_some() && !self.peek_current(TokenKind::RightParentheses) {
|
||||
arguments.push(self.expression()?);
|
||||
if let Some(current) = &self.current {
|
||||
if matches!(
|
||||
current.kind(),
|
||||
TokenKind::IntegerLiteral | TokenKind::String | TokenKind::Identifier
|
||||
) {
|
||||
arguments.append(&mut self.expression_list()?);
|
||||
}
|
||||
}
|
||||
let right_parentheses_token = self.expect_advance(TokenKind::RightParentheses)?;
|
||||
let source_range =
|
||||
SourceRange::new(callee.source_range().start(), right_parentheses_token.end());
|
||||
Ok(Call::new(callee, arguments, source_range))
|
||||
}
|
||||
|
||||
fn expression_list(&mut self) -> Result<Vec<Expression>, Vec<Diagnostic>> {
|
||||
let mut expressions = vec![];
|
||||
expressions.push(self.expression()?);
|
||||
while self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
||||
self.advance(); // comma
|
||||
expressions.push(self.expression()?);
|
||||
}
|
||||
Ok(expressions)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -483,7 +512,7 @@ mod smoke_tests {
|
||||
|
||||
#[test]
|
||||
fn extern_fn_with_param() {
|
||||
smoke_test("extern fn println(message: Any)");
|
||||
smoke_test("extern fn println(message: Any) -> Void");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -495,6 +524,21 @@ mod smoke_tests {
|
||||
fn fn_with_params() {
|
||||
smoke_test("fn foo(bar: Int, baz: Int) end");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_type() {
|
||||
smoke_test("fn foo() -> Int end")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extern_return_type() {
|
||||
smoke_test("extern fn foo() -> Int");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_two_numbers() {
|
||||
smoke_test("fn main() 1 + 2 end");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -503,7 +547,7 @@ mod concrete_tests {
|
||||
|
||||
#[test]
|
||||
fn parses_extern_fn() {
|
||||
let parse_result = parse_compilation_unit("extern fn println()");
|
||||
let parse_result = parse_compilation_unit("extern fn println() -> Void");
|
||||
let compilation_unit = match parse_result {
|
||||
Ok(compilation_unit) => compilation_unit,
|
||||
Err(diagnostics) => {
|
||||
|
||||
@ -6,14 +6,16 @@ pub struct FunctionSymbol {
|
||||
name: Rc<str>,
|
||||
is_platform: bool,
|
||||
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
|
||||
return_type: TypeInfo,
|
||||
}
|
||||
|
||||
impl FunctionSymbol {
|
||||
pub fn new(name: &str, is_platform: bool) -> Self {
|
||||
pub fn new(name: &str, is_platform: bool, return_type: TypeInfo) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
is_platform,
|
||||
parameters: None,
|
||||
return_type,
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +36,7 @@ impl FunctionSymbol {
|
||||
}
|
||||
|
||||
pub fn return_type(&self) -> TypeInfo {
|
||||
todo!()
|
||||
self.return_type.clone()
|
||||
}
|
||||
|
||||
pub fn is_platform(&self) -> bool {
|
||||
|
||||
@ -38,4 +38,6 @@ pub enum TokenKind {
|
||||
Extern,
|
||||
Comma,
|
||||
Colon,
|
||||
RightArrow,
|
||||
Plus,
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ pub enum TypeInfo {
|
||||
Integer,
|
||||
String,
|
||||
Function(Rc<RefCell<FunctionSymbol>>),
|
||||
Void,
|
||||
}
|
||||
|
||||
impl Display for TypeInfo {
|
||||
@ -24,6 +25,7 @@ impl Display for TypeInfo {
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
TypeInfo::Void => write!(f, "Void"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,6 +37,7 @@ impl TypeInfo {
|
||||
"Any" => TypeInfo::Any,
|
||||
"Int" => TypeInfo::Integer,
|
||||
"String" => TypeInfo::String,
|
||||
"Void" => TypeInfo::Void,
|
||||
_ => panic!("Unknown type: {}", declared_name),
|
||||
}
|
||||
}
|
||||
@ -51,6 +54,25 @@ impl TypeInfo {
|
||||
TypeInfo::Function(_) => {
|
||||
unimplemented!("Type matching on Functions not yet supported.")
|
||||
}
|
||||
TypeInfo::Void => {
|
||||
matches!(other, TypeInfo::Void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_add(&self, rhs: &Self) -> bool {
|
||||
match self {
|
||||
TypeInfo::Integer => matches!(rhs, TypeInfo::Integer),
|
||||
TypeInfo::String => matches!(rhs, TypeInfo::String | TypeInfo::Integer),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn additive_result(&self, _rhs: &Self) -> TypeInfo {
|
||||
match self {
|
||||
TypeInfo::Integer => TypeInfo::Integer,
|
||||
TypeInfo::String => TypeInfo::String,
|
||||
_ => panic!("Adding things other than integers and strings not yet supported"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,9 +14,14 @@ pub enum Instruction {
|
||||
PushInt(i32),
|
||||
PushStackFrameOffset(isize),
|
||||
|
||||
InvokeStatic(FunctionName),
|
||||
InvokePlatformStatic(FunctionName, ArgCount),
|
||||
|
||||
LoadStringConstant(ConstantName, Register),
|
||||
|
||||
Pop(Option<Register>),
|
||||
|
||||
AddIntInt(Register, Register, Register),
|
||||
AddStringInt(Register, Register, Register),
|
||||
AddStringString(Register, Register, Register),
|
||||
}
|
||||
|
||||
@ -174,6 +174,14 @@ pub fn call(
|
||||
}
|
||||
|
||||
/* Invoke instructions */
|
||||
Instruction::InvokeStatic(function_name) => {
|
||||
let function = context
|
||||
.functions
|
||||
.get(function_name)
|
||||
.expect(&format!("Function {} not found", function_name));
|
||||
todo!("Call stack for invoking Deimos-native functions")
|
||||
}
|
||||
|
||||
Instruction::InvokePlatformStatic(function_name, arg_count) => {
|
||||
let stack = state.stack();
|
||||
let args = &stack[stack.len() - arg_count..];
|
||||
@ -210,6 +218,26 @@ pub fn call(
|
||||
}
|
||||
}
|
||||
|
||||
/* Add instructions */
|
||||
Instruction::AddIntInt(lhs, rhs, destination) => {
|
||||
let lhs_value = state.registers()[*lhs].unwrap_int();
|
||||
let rhs_value = state.registers()[*rhs].unwrap_int();
|
||||
let result = lhs_value + rhs_value;
|
||||
state.registers_mut()[*destination] = Value::Int(result);
|
||||
}
|
||||
Instruction::AddStringInt(lhs, rhs, destination) => {
|
||||
let lhs_value = state.registers()[*lhs].unwrap_string();
|
||||
let rhs_value = state.registers()[*rhs].unwrap_int();
|
||||
let formatted = format!("{}{}", lhs_value, rhs_value);
|
||||
state.registers_mut()[*destination] = Value::String(Rc::from(formatted));
|
||||
}
|
||||
Instruction::AddStringString(lhs, rhs, destination) => {
|
||||
let lhs_value = state.registers()[*lhs].unwrap_string();
|
||||
let rhs_value = state.registers()[*rhs].unwrap_string();
|
||||
let formatted = format!("{}{}", lhs_value, rhs_value);
|
||||
state.registers_mut()[*destination] = Value::String(Rc::from(formatted));
|
||||
}
|
||||
|
||||
/* Pop instructions */
|
||||
Instruction::Pop(maybe_register) => {
|
||||
let value = state.stack_mut().pop().unwrap();
|
||||
|
||||
@ -12,3 +12,19 @@ impl Default for Value {
|
||||
Value::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn unwrap_int(&self) -> i32 {
|
||||
match self {
|
||||
Value::Int(i) => *i,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_string(&self) -> &Rc<str> {
|
||||
match self {
|
||||
Value::String(s) => s,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5
examples/add.dm
Normal file
5
examples/add.dm
Normal file
@ -0,0 +1,5 @@
|
||||
extern fn println(message: Any) -> Void
|
||||
|
||||
fn main()
|
||||
println(6 + 7)
|
||||
end
|
||||
9
examples/call.dm
Normal file
9
examples/call.dm
Normal file
@ -0,0 +1,9 @@
|
||||
extern fn println(message: Any) -> Void
|
||||
|
||||
fn add(a: Int, b: Int) -> Int
|
||||
a + b
|
||||
end
|
||||
|
||||
fn main()
|
||||
println(add(1, 2))
|
||||
end
|
||||
Loading…
Reference in New Issue
Block a user