From ad80498e093334aaff20bb91e04ece04140dd5ad Mon Sep 17 00:00:00 2001 From: Robert-M-Lucas Date: Sat, 8 Jun 2024 07:51:33 +0100 Subject: [PATCH] Improved operator support --- .idea/workspace.xml | 73 +++++++++++------- build/out.asm | 50 +++--------- build/out.o | Bin 784 -> 688 bytes build/out.out | Bin 16536 -> 16512 bytes main.why | 11 +-- src/root/builtin/int/add.rs | 1 + src/root/builtin/int/mod.rs | 3 + src/root/builtin/int/sub.rs | 46 +++++++++++ src/root/compiler/compile_evaluable.rs | 52 +++++++++---- src/root/compiler/compile_function.rs | 10 ++- src/root/errors/evaluable_errors.rs | 4 +- .../resolve_function_signatures.rs | 6 +- src/root/parser/parse_function.rs | 4 +- src/root/parser/parse_parameters.rs | 7 +- src/root/parser/parse_struct.rs | 2 +- todo.txt | 4 +- types.toml | 1 + 17 files changed, 180 insertions(+), 94 deletions(-) create mode 100644 src/root/builtin/int/sub.rs diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 32da7bd..a777d00 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -7,16 +7,24 @@ - + + - - - + + + + + + + + + + - { - "keyToString": { - "Cargo.Run whython-8.executor": "Run", - "RunOnceActivity.OpenProjectViewOnStart": "true", - "RunOnceActivity.ShowReadmeOnStart": "true", - "RunOnceActivity.rust.reset.selective.auto.import": "true", - "git-widget-placeholder": "master", - "ignore.virus.scanning.warn.message": "true", - "node.js.detected.package.eslint": "true", - "node.js.detected.package.tslint": "true", - "node.js.selected.package.eslint": "(autodetect)", - "node.js.selected.package.tslint": "(autodetect)", - "nodejs_package_manager_path": "npm", - "org.rust.cargo.project.model.PROJECT_DISCOVERY": "true", - "org.rust.cargo.project.model.impl.CargoExternalSystemProjectAware.subscribe.first.balloon": "", - "org.rust.first.attach.projects": "true", - "settings.editor.selected.configurable": "preferences.pluginManager", - "vue.rearranger.settings.migration": "true" + +}]]> + + + @@ -167,7 +179,7 @@ - + - @@ -403,6 +423,7 @@ - \ No newline at end of file diff --git a/build/out.asm b/build/out.asm index e2b8171..c5a754c 100644 --- a/build/out.asm +++ b/build/out.asm @@ -2,40 +2,21 @@ section .text -_2: - push rbp - mov rbp, rsp - - mov rax, qword [rbp+16] - mov qword [rbp-16], rax - mov rax, qword [rbp+24] - mov qword [rbp-24], rax - mov rax, qword [rbp-16] - add rax, qword [rbp-24] - mov qword [rbp-8], rax - mov qword [rbp-32], 1 - mov rax, qword [rbp-8] - add rax, qword [rbp-32] - mov qword [rbp+32], rax - leave - ret - main: push rbp mov rbp, rsp - mov qword [rbp-16], 3 - mov qword [rbp-24], 2 - mov rax, qword [rbp-16] - mov qword [rbp-48], rax + mov qword [rbp-8], -12 + mov rax, qword [rbp-8] + mov qword [rbp-24], rax mov rax, qword [rbp-24] - mov qword [rbp-56], rax - sub rsp, 56 + mov qword [rbp-40], rax + sub rsp, 40 call _1 - add rsp, 56 - mov rax, qword [rbp-40] - mov qword [rbp-8], rax - mov rax, qword [rbp-8] + add rsp, 40 + mov rax, qword [rbp-32] + mov qword [rbp-16], rax + mov rax, qword [rbp-16] leave ret @@ -43,19 +24,12 @@ _1: push rbp mov rbp, rsp + mov qword [rbp-8], 0 mov rax, qword [rbp+16] - mov qword [rbp-8], rax - mov rax, qword [rbp+24] mov qword [rbp-16], rax mov rax, qword [rbp-8] - mov qword [rbp-40], rax - mov rax, qword [rbp-16] - mov qword [rbp-48], rax - sub rsp, 48 - call _2 - add rsp, 48 - mov rax, qword [rbp-32] - mov qword [rbp+32], rax + sub rax, qword [rbp-16] + mov qword [rbp+24], rax leave ret diff --git a/build/out.o b/build/out.o index 0567760732e8eb7982293579a4fbcd5924f85fd7..1c6972f68f4b3f05789df78a8d7e4ed354192628 100644 GIT binary patch delta 220 zcmbQhwt;oR0>;RR3(c7xFiyN>Cn~_i00tEhih%`4vrN`y)aIN3l@Xtu$fy#1-1Wzo z|NsAcbi4lW=yZJnq+bB(8y?MXG+qb+^>{QN(EtiQ01AEp(jQJ94)y4K>H*XSG8iZ# z0G0XSp$$~g=_+yZFh~XnCL1tS$cuoPj11;r8bR;_nF0)q6CI`GlS(slQuOmnOY{

%v!7n(B}FipH=Cz`;-00t8v6ax#8W}U3dsLlBSDkC*Hkx`|-+f~4$ z)AfT#x2pt@egULEcrXL$PS+nE$6X&V0<{6fegMTD0L2te9uD>BdjfYU(s{z8`HjU3A&^A#5euN;4X|-QW1!k0mi_?B=zwem+5Q7a-vH7dfb<2R zeuEcr|Ns97>NfxiLamkAB{m-rbl{u3fF)#;LIEFR&gMeB{mh&> zf({@}3?-8rjie`s7^!e(LPat`BB;E{2aHs>OQ7V}iU&12MW$6`x`bFtP9kUewnOju2HC4^{}0aR^RLt{NBktTZqV0*mosBw UD<=i`h^93eKA-fnJCqIm1-pQ&AOHXW diff --git a/main.why b/main.why index e7dda27..fa319d3 100644 --- a/main.why +++ b/main.why @@ -1,14 +1,11 @@ impl int { - fn sub(lhs: int, rhs: int) -> int { - return lhs == rhs; - } - - fn eq(lhs: int, rhs: int) -> int { - return (lhs + rhs) + 1; + fn p_sub(self) -> Self { + return 0 - self; } } fn main() -> int { - return 3 - 2; + let x: int = -12; + return -x; } diff --git a/src/root/builtin/int/add.rs b/src/root/builtin/int/add.rs index f68aa72..af8cb79 100644 --- a/src/root/builtin/int/add.rs +++ b/src/root/builtin/int/add.rs @@ -22,6 +22,7 @@ impl BuiltinInlineFunction for IntAdd { fn signature(&self) -> FunctionSignature { FunctionSignature::new_inline_builtin( + true, &[("lhs", IntType::id().immediate()), ("rhs", IntType::id().immediate())], Some(IntType::id().immediate()) ) diff --git a/src/root/builtin/int/mod.rs b/src/root/builtin/int/mod.rs index 53ca065..bbcbaa3 100644 --- a/src/root/builtin/int/mod.rs +++ b/src/root/builtin/int/mod.rs @@ -1,8 +1,10 @@ mod add; +mod sub; use b_box::b; use unique_type_id::UniqueTypeId; use crate::root::builtin::int::add::IntAdd; +use crate::root::builtin::int::sub::IntSub; use crate::root::errors::WErr; use crate::root::name_resolver::name_resolvers::GlobalDefinitionTable; use crate::root::parser::parse_function::parse_literal::{LiteralToken, LiteralTokens}; @@ -12,6 +14,7 @@ use crate::root::shared::types::Type; pub fn register_int(global_table: &mut GlobalDefinitionTable) { global_table.register_builtin_type(b!(IntType)); global_table.register_inline_function(&IntAdd); + global_table.register_inline_function(&IntSub); } #[derive(UniqueTypeId)] diff --git a/src/root/builtin/int/sub.rs b/src/root/builtin/int/sub.rs new file mode 100644 index 0000000..bb7b367 --- /dev/null +++ b/src/root/builtin/int/sub.rs @@ -0,0 +1,46 @@ +use unique_type_id::UniqueTypeId; +use crate::root::builtin::{BuiltinInlineFunction, InlineFunctionGenerator}; +use crate::root::builtin::int::IntType; +use crate::root::errors::WErr; +use crate::root::name_resolver::name_resolvers::NameResult::Function; +use crate::root::name_resolver::resolve_function_signatures::FunctionSignature; + +use crate::root::shared::common::{FunctionID, Indirection, LocalAddress, TypeID, TypeRef}; + +#[derive(UniqueTypeId)] +#[UniqueTypeIdType = "u16"] +pub struct IntSub; + +impl BuiltinInlineFunction for IntSub { + fn id(&self) -> FunctionID { + FunctionID(-(IntSub::unique_type_id().0 as isize) - 1) + } + + fn name(&self) -> &'static str { + "sub" + } + + fn signature(&self) -> FunctionSignature { + FunctionSignature::new_inline_builtin( + true, + &[("lhs", IntType::id().immediate()), ("rhs", IntType::id().immediate())], + Some(IntType::id().immediate()) + ) + } + + fn inline(&self) -> InlineFunctionGenerator { + |args: &[LocalAddress], return_into: Option| -> String { + let lhs = args[0]; + let rhs = args[1]; + let return_into = return_into.unwrap(); + format!( +" mov rax, qword {lhs} + sub rax, qword {rhs} + mov qword {return_into}, rax") + } + } + + fn parent_type(&self) -> Option { + Some(IntType::id()) + } +} diff --git a/src/root/compiler/compile_evaluable.rs b/src/root/compiler/compile_evaluable.rs index 920e403..17e2847 100644 --- a/src/root/compiler/compile_evaluable.rs +++ b/src/root/compiler/compile_evaluable.rs @@ -90,22 +90,16 @@ pub fn compile_evaluable_into( t.instantiate_from_literal(target.local_address(), literal)? } EvaluableTokens::InfixOperator(lhs, op, rhs) => { - // if op.is_prefix_opt_t() { - // return Err(WErr::n(EvalErrs::FoundPrefixNotInfixOp(op.operator().to_str().to_string()), op.location().clone())); - // } - let mut code = String::new(); - // let (mut code, lhs) = compile_evaluable(fid, lhs, local_variables, global_table, function_calls)?; let lhs_type = compile_evaluable_type_only(fid, lhs, local_variables, global_table, function_calls)?; - // code += "\n"; let op_fn = global_table.get_operator_function(*lhs_type.type_id(), op, PrefixOrInfixEx::Infix)?; let signature = global_table.get_function_signature(op_fn); if signature.args().len() != 2 { return Err( WErr::n( - EvalErrs::OpWrongArgumentCount( + EvalErrs::InfixOpWrongArgumentCount( op.operator().to_str().to_string(), global_table.get_type(*lhs_type.type_id()).name().to_string(), op.operator().get_method_name(PrefixOrInfixEx::Infix).unwrap(), @@ -127,18 +121,50 @@ pub fn compile_evaluable_into( } } - // let rhs_type_target = signature.args()[1].1.clone(); - // let rhs_box = global_table.add_local_variable_unnamed_base(rhs_type_target, local_variables); - // code += &compile_evaluable_into(fid, rhs, rhs_box.clone(), local_variables, global_table, function_calls)?; - // code += "\n"; - let (c, _) = call_function(fid, op_fn, &[Left(lhs), Left(rhs)], Some(target), global_table, local_variables, function_calls)?; code += &c; code }, - EvaluableTokens::PrefixOperator(_, _) => todo!(), + EvaluableTokens::PrefixOperator(op, lhs) => { + let mut code = String::new(); + + let lhs_type = compile_evaluable_type_only(fid, lhs, local_variables, global_table, function_calls)?; + let op_fn = global_table.get_operator_function(*lhs_type.type_id(), op, PrefixOrInfixEx::Prefix)?; + let signature = global_table.get_function_signature(op_fn); + + if signature.args().len() != 1 { + return Err( + WErr::n( + EvalErrs::InfixOpWrongArgumentCount( + op.operator().to_str().to_string(), + global_table.get_type(*lhs_type.type_id()).name().to_string(), + op.operator().get_method_name(PrefixOrInfixEx::Prefix).unwrap(), + signature.args().len() + ), + op.location().clone() + ) + ); + } + + match signature.return_type() { + None => { + return Err(WErr::n(OpNoReturn(global_table.get_type_name(target.type_ref())), op.location().clone())) + } + Some(rt) => { + if rt != target.type_ref() { + return Err(WErr::n(OpWrongReturnType(global_table.get_type_name(target.type_ref()), global_table.get_type_name(rt)), op.location().clone())) + } + } + } + + let (c, _) = call_function(fid, op_fn, &[Left(lhs)], Some(target), global_table, local_variables, function_calls)?; + + code += &c; + + code + }, EvaluableTokens::DynamicAccess(_, _) => todo!(), // Accessed methods must be called EvaluableTokens::StaticAccess(_, n) => return Err(WErr::n(NRErrors::CannotFindConstantAttribute(n.name().clone()), n.location().clone())), // Accessed methods must be called EvaluableTokens::FunctionCall(inner, args) => { diff --git a/src/root/compiler/compile_function.rs b/src/root/compiler/compile_function.rs index c584b57..5d78c47 100644 --- a/src/root/compiler/compile_function.rs +++ b/src/root/compiler/compile_function.rs @@ -13,7 +13,7 @@ use crate::root::shared::common::AddressedTypeRef; pub fn compile_function(fid: FunctionID, function: FunctionToken, global_table: &mut GlobalDefinitionTable) -> Result<(String, HashSet), WErr> { let mut local_variables = LocalVariableTable::new(); - let (_location, _name, return_type, parameters, lines) = function.dissolve(); + let (_location, _name, return_type, _, parameters, lines) = function.dissolve(); let return_type = if fid.is_main() { None } else { return_type }; @@ -67,7 +67,10 @@ fn recursively_compile_lines(fid: FunctionID, lines: &[LineTokens], return_varia local_variables.enter_block(); let mut contents = String::new(); + let mut last_is_return = false; + for line in lines { + last_is_return = false; match line { LineTokens::Initialisation(it) => { let (name, type_name, value) = (it.name(), it.type_name(), it.value()); @@ -79,6 +82,7 @@ fn recursively_compile_lines(fid: FunctionID, lines: &[LineTokens], return_varia LineTokens::If(_) => todo!(), LineTokens::While(_) => todo!(), LineTokens::Return(rt) => { + last_is_return = true; if fid.is_main() { if rt.return_value().is_none() { todo!() @@ -118,6 +122,10 @@ fn recursively_compile_lines(fid: FunctionID, lines: &[LineTokens], return_varia } } + if (return_variable.is_some() || fid.is_main()) && !last_is_return { + todo!() + } + local_variables.leave_block(); Ok(contents) diff --git a/src/root/errors/evaluable_errors.rs b/src/root/errors/evaluable_errors.rs index 3219b9c..6787597 100644 --- a/src/root/errors/evaluable_errors.rs +++ b/src/root/errors/evaluable_errors.rs @@ -11,7 +11,9 @@ pub enum EvalErrs { // #[error("Operator ({0}) can only be used as a prefix operator, not infix")] // FoundPrefixNotInfixOp(String), #[error("Infix operator ({0}) can only be used for type ({1}) if method ({2}) accepting 2 arguments is implemented for ({1}). ({2}) implementation only accepts ({3}) arguments")] - OpWrongArgumentCount(String, String, String, usize), + InfixOpWrongArgumentCount(String, String, String, usize), + #[error("Prefix operator ({0}) can only be used for type ({1}) if method ({2}) accepting 1 arguments is implemented for ({1}). ({2}) implementation only accepts ({3}) arguments")] + PrefixOpWrongArgumentCount(String, String, String, usize), #[error("Expected operation to return type ({0}) but found ({1})")] OpWrongReturnType(String, String), #[error("Expected operation to return type ({0}) but found no return")] diff --git a/src/root/name_resolver/resolve_function_signatures.rs b/src/root/name_resolver/resolve_function_signatures.rs index d71c5a9..02dd486 100644 --- a/src/root/name_resolver/resolve_function_signatures.rs +++ b/src/root/name_resolver/resolve_function_signatures.rs @@ -8,13 +8,15 @@ use crate::root::parser::parse_name::SimpleNameToken; #[derive(Getters)] pub struct FunctionSignature { + dynamic: bool, args: Vec<(SimpleNameToken, TypeRef)>, return_type: Option } impl FunctionSignature { - pub fn new_inline_builtin(args: &[(&str, TypeRef)], return_type: Option) -> FunctionSignature { + pub fn new_inline_builtin(dynamic: bool, args: &[(&str, TypeRef)], return_type: Option) -> FunctionSignature { FunctionSignature { + dynamic, args: args.into_iter().map(|(name, t)| (SimpleNameToken::new_builtin(name.to_string()), t.clone())).collect_vec(), return_type } @@ -37,7 +39,9 @@ pub fn resolve_function_signature(function_token: &FunctionToken, global_table: )) } + Ok(FunctionSignature { + dynamic: *function_token.dynamic(), args, return_type }) diff --git a/src/root/parser/parse_function.rs b/src/root/parser/parse_function.rs index 33cb8ac..61e747b 100644 --- a/src/root/parser/parse_function.rs +++ b/src/root/parser/parse_function.rs @@ -29,6 +29,7 @@ pub struct FunctionToken { location: Location, name: SimpleNameToken, return_type: Option, + dynamic: bool, parameters: Parameters, lines: Vec, } @@ -54,7 +55,7 @@ pub fn parse_function<'a, 'b>(s: Span<'a>, allow_self: Option<&'b SimpleNameToke // } else { None }; let (s, contents) = default_section(s, '(')?; - let (_, parameters) = parse_parameters(contents, allow_self)?; + let (_, (parameters, has_self)) = parse_parameters(contents, allow_self)?; let (s, _) = discard_ignored(s)?; @@ -74,6 +75,7 @@ pub fn parse_function<'a, 'b>(s: Span<'a>, allow_self: Option<&'b SimpleNameToke Ok(( s, FunctionToken { + dynamic: has_self, location, name, return_type, diff --git a/src/root/parser/parse_parameters.rs b/src/root/parser/parse_parameters.rs index 3218d3e..a4799dc 100644 --- a/src/root/parser/parse_parameters.rs +++ b/src/root/parser/parse_parameters.rs @@ -7,15 +7,18 @@ use crate::root::parser::parse_util::discard_ignored; pub type Parameters = Vec<(SimpleNameToken, FullNameWithIndirectionToken)>; -pub fn parse_parameters<'a, 'b>(s: Span<'a>, mut allow_self: Option<&'b SimpleNameToken>) -> ParseResult<'a, (), Parameters> { +pub fn parse_parameters<'a, 'b>(s: Span<'a>, mut allow_self: Option<&'b SimpleNameToken>) -> ParseResult<'a, (), (Parameters, bool)> { let (mut s, _) = discard_ignored(s)?; let mut parameters = Vec::new(); + let mut has_self = false; + while !s.is_empty() { let (ns, name) = parse_simple_name(s)?; let (ns, p_type) = if allow_self.is_some() && parameters.is_empty() && *name.name() == "self" { + has_self = true; let s = allow_self.take().unwrap(); (ns, FullNameWithIndirectionToken::from_simple(s.clone(), Some(s.clone()), name.location().clone())) } @@ -40,5 +43,5 @@ pub fn parse_parameters<'a, 'b>(s: Span<'a>, mut allow_self: Option<&'b SimpleNa s = ns; } - Ok(((), parameters)) + Ok(((), (parameters, has_self))) } diff --git a/src/root/parser/parse_struct.rs b/src/root/parser/parse_struct.rs index 92d8677..1c2e23c 100644 --- a/src/root/parser/parse_struct.rs +++ b/src/root/parser/parse_struct.rs @@ -40,7 +40,7 @@ pub fn parse_struct(s: Span) -> ParseResult { let (s, name) = parse_simple_name(s)?; let (s, _) = discard_ignored(s)?; let (s, contents) = default_section(s, '{')?; - let (_, parameters) = parse_parameters(contents, None)?; + let (_, (parameters, _)) = parse_parameters(contents, None)?; Ok(( s, diff --git a/todo.txt b/todo.txt index bac6808..2cb0a51 100644 --- a/todo.txt +++ b/todo.txt @@ -1,9 +1,7 @@ -3. Allow operators to be both prefix and infix i.e. -a or a - b +3. Add function/method calling 4. Finish off evaluable compilation 5. Finish of handling of remaining lines 6. Add rich parser errors 7. Add all errors in 8. All other todos, of course - -?. Add support for multiple functions with the same name but different signatures ? \ No newline at end of file diff --git a/types.toml b/types.toml index 977876b..bbec0b9 100644 --- a/types.toml +++ b/types.toml @@ -1,2 +1,3 @@ IntType=0 IntAdd=1 +IntSub=2