Skip to content

Commit

Permalink
Improved operator support
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert-M-Lucas committed Jun 8, 2024
1 parent 63afc58 commit b573fba
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 59 deletions.
27 changes: 24 additions & 3 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 18 additions & 18 deletions build/out.asm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

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
Expand Down Expand Up @@ -41,21 +59,3 @@ _1:
leave
ret

_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

Binary file modified build/out.o
Binary file not shown.
Binary file modified build/out.out
Binary file not shown.
2 changes: 1 addition & 1 deletion main.why
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ impl int {
}

fn eq(lhs: int, rhs: int) -> int {
return lhs + rhs + 1;
return (lhs + rhs) + 1;
}
}

Expand Down
19 changes: 10 additions & 9 deletions src/root/compiler/compile_evaluable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::root::errors::name_resolver_errors::NRErrors;
use crate::root::errors::WErr;
use crate::root::name_resolver::name_resolvers::{GlobalDefinitionTable, NameResult};
use crate::root::parser::parse_function::parse_evaluable::{EvaluableToken, EvaluableTokens};
use crate::root::parser::parse_function::parse_operator::PrefixOrInfixEx;
use crate::root::shared::common::{FunctionID, Indirection, TypeRef};
use crate::root::shared::common::AddressedTypeRef;

Expand Down Expand Up @@ -89,16 +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()));
}
// 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)?;
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 {
Expand All @@ -107,7 +108,7 @@ pub fn compile_evaluable_into(
EvalErrs::OpWrongArgumentCount(
op.operator().to_str().to_string(),
global_table.get_type(*lhs_type.type_id()).name().to_string(),
op.operator().get_method_name().to_string(),
op.operator().get_method_name(PrefixOrInfixEx::Infix).unwrap(),
signature.args().len()
),
op.location().clone()
Expand Down Expand Up @@ -218,14 +219,14 @@ pub fn compile_evaluable_type_only(
TypeRef::new(tid.clone(), Indirection(0))
}
EvaluableTokens::InfixOperator(lhs, op, _) => {
if op.is_prefix_opt_t() {
return Err(WErr::n(EvalErrs::FoundPrefixNotInfixOp(op.operator().to_str().to_string()), op.location().clone()));
}
// if op.is_prefix_opt_t() {
// return Err(WErr::n(EvalErrs::FoundPrefixNotInfixOp(op.operator().to_str().to_string()), op.location().clone()));
// }

// 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)?;
let op_fn = global_table.get_operator_function(*lhs_type.type_id(), op, PrefixOrInfixEx::Infix)?;
let signature = global_table.get_function_signature(op_fn);
signature.return_type().as_ref().unwrap().clone()
},
Expand Down
4 changes: 2 additions & 2 deletions src/root/errors/evaluable_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ pub enum EvalErrs {
FunctionMustBeCalled(String),
#[error("Cannot evaluate a standalone type ({0})")]
CannotEvalStandaloneType(String),
#[error("Operator ({0}) can only be used as a prefix operator, not infix")]
FoundPrefixNotInfixOp(String),
// #[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),
#[error("Expected operation to return type ({0}) but found ({1})")]
Expand Down
4 changes: 4 additions & 0 deletions src/root/errors/name_resolver_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ pub enum NRErrors {
CannotFindConstantAttribute(String),
#[error("Method ({0}) not implemented for type ({1}) required for operator ({2})")]
OpMethodNotImplemented(String, String, String),
#[error("Operator ({0}) cannot be used as a prefix operator")]
OpCantBePrefix(String),
#[error("Operator ({0}) cannot be used as an infix operator")]
OpCantBeInfix(String),
#[error("Size of type ({0}) cannot be determined due to circular definition with no indirection")]
CircularType(String)
}
27 changes: 18 additions & 9 deletions src/root/name_resolver/name_resolvers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::root::parser::parse::Location;
use crate::root::shared::types::Type;
use crate::root::parser::parse_function::FunctionToken;
use crate::root::parser::parse_function::parse_evaluable::{FullNameToken, FullNameTokens, FullNameWithIndirectionToken};
use crate::root::parser::parse_function::parse_operator::{OperatorToken};
use crate::root::parser::parse_function::parse_operator::{OperatorToken, PrefixOrInfixEx};
use crate::root::parser::parse_name::SimpleNameToken;
use crate::root::parser::parse_struct::StructToken;
use crate::root::POINTER_SIZE;
Expand Down Expand Up @@ -310,14 +310,23 @@ impl GlobalDefinitionTable {
Err(WErr::n(NRErrors::CannotFindName(name.name().clone()), name.location().clone()))
}

pub fn get_operator_function(&self, lhs: TypeID, operator: &OperatorToken) -> Result<FunctionID, WErr> {
let op_name = operator.operator().get_method_name();
self.impl_definitions.get(&lhs).and_then(|f| f.get(op_name)).ok_or(
WErr::n(
NRErrors::OpMethodNotImplemented(op_name.to_string(), self.get_type(lhs).name().to_string(), operator.operator().to_str().to_string()),
operator.location().clone()
)
).copied()
pub fn get_operator_function(&self, lhs: TypeID, operator: &OperatorToken, kind: PrefixOrInfixEx) -> Result<FunctionID, WErr> {
let op_name = operator.operator().get_method_name(kind);

if let Some(op_name) = op_name {
self.impl_definitions.get(&lhs).and_then(|f| f.get(&op_name)).ok_or(
WErr::n(
NRErrors::OpMethodNotImplemented(op_name.to_string(), self.get_type(lhs).name().to_string(), operator.operator().to_str().to_string()),
operator.location().clone()
)
).copied()
}
else {
Err(WErr::n(match kind {
PrefixOrInfixEx::Prefix => NRErrors::OpCantBePrefix(operator.operator().to_str().to_string()),
PrefixOrInfixEx::Infix => NRErrors::OpCantBeInfix(operator.operator().to_str().to_string()),
}, operator.location().clone()))
}
}

pub fn get_function(&self, function: FunctionID) -> (&FunctionSignature, Option<&InlineFunctionGenerator>) {
Expand Down
4 changes: 3 additions & 1 deletion src/root/parser/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::rc::Rc;
use color_print::cformat;
use derive_getters::Getters;
use lazy_static::lazy_static;
use nom_supreme::final_parser::ExtractContext;
use crate::root::errors::parser_errors::ParseError;
use crate::root::errors::WErr;
use crate::root::parser::parse_toplevel::TopLevelTokens;
Expand Down Expand Up @@ -166,8 +167,9 @@ pub fn parse(path: PathBuf) -> Result<Vec<TopLevelTokens>, WErr> {

let (remaining, output) = match parse_toplevel::parse_toplevel(base) {
Ok(v) => v,
Err(_) => {
Err(e) => {
// TODO:
println!("{:?}", e);
return Err(WErr::n(ParseError::ParserErrorsNotImplemented, Location::builtin()));
}
};
Expand Down
8 changes: 5 additions & 3 deletions src/root/parser/parse_function/parse_evaluable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ pub fn parse_evaluable<'a, 'b>(s: Span<'a>, containing_class: Option<&SimpleName
}

// Recursively parse bracketed sections
let ns = if let Ok((ns, _)) = default_section(s, '(') {
let (ns, evaluable) = parse_evaluable(ns, containing_class.clone(), false)?;
let ns = if let Ok((ns, inner)) = default_section(s, '(') {
let (_, evaluable) = parse_evaluable(inner, containing_class.clone(), false)?;
evaluables.push(TempEvaluableTokensOne::EvaluableToken(evaluable));
ns
}
Expand Down Expand Up @@ -465,5 +465,7 @@ pub fn parse_evaluable<'a, 'b>(s: Span<'a>, containing_class: Option<&SimpleName
}
}

Ok((s, recursively_convert_temp(base.unwrap(), &mut evaluables)))
let conv = recursively_convert_temp(base.unwrap(), &mut evaluables);

Ok((s, conv))
}
67 changes: 58 additions & 9 deletions src/root/parser/parse_function/parse_operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@ use nom_supreme::error::GenericErrorTree;
use nom_supreme::tag::complete::tag;
use nom_supreme::tag::TagError;

const OPERATOR_MAPS: [(&str, OperatorTokens, bool, &'static str); 4] = [
("+", OperatorTokens::Add, false, "add"),
("-", OperatorTokens::Subtract, false, "sub"),
("==", OperatorTokens::Equals, false, "eq"),
("!", OperatorTokens::Not, true, "not"),
#[derive(PartialEq, Debug)]
pub enum PrefixOrInfix {
Prefix,
Infix,
Both
}

#[derive(Copy, Clone, Debug)]
pub enum PrefixOrInfixEx {
Prefix,
Infix
}

const OPERATOR_MAPS: [(&str, OperatorTokens, PrefixOrInfix, &'static str); 4] = [
("+", OperatorTokens::Add, PrefixOrInfix::Both, "add"),
("-", OperatorTokens::Subtract, PrefixOrInfix::Both, "sub"),
("==", OperatorTokens::Equals, PrefixOrInfix::Infix, "eq"),
("!", OperatorTokens::Not, PrefixOrInfix::Prefix, "not"),
];

#[derive(Debug, Clone, Getters)]
Expand Down Expand Up @@ -43,21 +56,57 @@ impl OperatorTokens {
pub fn is_prefix_op(&self) -> bool {
for (_, op, prefix, _) in &OPERATOR_MAPS {
if self == op {
return *prefix;
return match prefix {
PrefixOrInfix::Prefix => true,
PrefixOrInfix::Infix => false,
PrefixOrInfix::Both => true
}
}
}
panic!()
}

pub fn get_method_name(&self) -> &'static str {
for (_, op, _, name) in &OPERATOR_MAPS {
pub fn is_infix_op(&self) -> bool {
for (_, op, prefix, _) in &OPERATOR_MAPS {
if self == op {
return *name;
return match prefix {
PrefixOrInfix::Prefix => false,
PrefixOrInfix::Infix => true,
PrefixOrInfix::Both => true
}
}
}
panic!()
}

pub fn get_method_name(&self, kind: PrefixOrInfixEx) -> Option<String> {
for (_, op, p_kind, name) in &OPERATOR_MAPS {
if self == op {
return match p_kind {
PrefixOrInfix::Prefix => {
match kind {
PrefixOrInfixEx::Prefix => Some(format!("p_{name}")),
PrefixOrInfixEx::Infix => None
}
}
PrefixOrInfix::Infix => {
match kind {
PrefixOrInfixEx::Prefix => None,
PrefixOrInfixEx::Infix => Some(name.to_string())
}
}
PrefixOrInfix::Both => {
match kind {
PrefixOrInfixEx::Prefix => Some(format!("p_{name}")),
PrefixOrInfixEx::Infix => Some(name.to_string())
}
}
};
}
}
None
}

pub fn get_priority(&self) -> usize {
for (p, (_, op, _, _)) in OPERATOR_MAPS.iter().enumerate() {
if self == op {
Expand Down
9 changes: 5 additions & 4 deletions todo.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
1. Add support for multiple functions with the same name but different signatures
2. Allow operators to be both prefix and infix i.e. -a or a - b
3. Fix evaluables such as (a + b) or (a + b) + c not working

3. Allow operators to be both prefix and infix i.e. -a or a - b
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
8. All other todos, of course

?. Add support for multiple functions with the same name but different signatures ?

0 comments on commit b573fba

Please sign in to comment.