diff --git a/nac3core/src/toplevel/builtins.rs b/nac3core/src/toplevel/builtins.rs new file mode 100644 index 000000000..d200aa122 --- /dev/null +++ b/nac3core/src/toplevel/builtins.rs @@ -0,0 +1,580 @@ +use std::cell::RefCell; +use inkwell::{IntPredicate, FloatPredicate}; +use crate::symbol_resolver::SymbolValue; +use super::*; + +type BuiltinInfo = ( + Vec<(Arc>, Option)>, + &'static [&'static str] +); + +pub fn get_built_ins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { + let int32 = primitives.0.int32; + let int64 = primitives.0.int64; + let float = primitives.0.float; + let boolean = primitives.0.bool; + let range = primitives.0.range; + let string = primitives.0.str; + let num_ty = primitives.1.get_fresh_var_with_range(&[int32, int64, float, boolean]); + let var_map: HashMap<_, _> = vec![(num_ty.1, num_ty.0)].into_iter().collect(); + + let top_level_def_list = vec![ + Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def( + 0, + None, + "int32".into(), + None, + ))), + Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def( + 1, + None, + "int64".into(), + None, + ))), + Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def( + 2, + None, + "float".into(), + None, + ))), + Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(3, None, "bool".into(), None))), + Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(4, None, "none".into(), None))), + Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def( + 5, + None, + "range".into(), + None, + ))), + Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(6, None, "str".into(), None))), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "int32".into(), + simple_name: "int32".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }], + ret: int32, + vars: var_map.clone(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new( + |ctx, _, fun, args| { + let int32 = ctx.primitives.int32; + let int64 = ctx.primitives.int64; + let float = ctx.primitives.float; + let boolean = ctx.primitives.bool; + let arg_ty = fun.0.args[0].ty; + let arg = args[0].1; + if ctx.unifier.unioned(arg_ty, boolean) { + Some( + ctx.builder + .build_int_s_extend( + arg.into_int_value(), + ctx.ctx.i32_type(), + "sext", + ) + .into(), + ) + } else if ctx.unifier.unioned(arg_ty, int32) { + Some(arg) + } else if ctx.unifier.unioned(arg_ty, int64) { + Some( + ctx.builder + .build_int_truncate( + arg.into_int_value(), + ctx.ctx.i32_type(), + "trunc", + ) + .into(), + ) + } else if ctx.unifier.unioned(arg_ty, float) { + let val = ctx + .builder + .build_float_to_signed_int( + arg.into_float_value(), + ctx.ctx.i32_type(), + "fptosi", + ) + .into(); + Some(val) + } else { + unreachable!() + } + }, + )))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "int64".into(), + simple_name: "int64".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }], + ret: int64, + vars: var_map.clone(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new( + |ctx, _, fun, args| { + let int32 = ctx.primitives.int32; + let int64 = ctx.primitives.int64; + let float = ctx.primitives.float; + let boolean = ctx.primitives.bool; + let arg_ty = fun.0.args[0].ty; + let arg = args[0].1; + if ctx.unifier.unioned(arg_ty, boolean) + || ctx.unifier.unioned(arg_ty, int32) + { + Some( + ctx.builder + .build_int_s_extend( + arg.into_int_value(), + ctx.ctx.i64_type(), + "sext", + ) + .into(), + ) + } else if ctx.unifier.unioned(arg_ty, int64) { + Some(arg) + } else if ctx.unifier.unioned(arg_ty, float) { + let val = ctx + .builder + .build_float_to_signed_int( + arg.into_float_value(), + ctx.ctx.i64_type(), + "fptosi", + ) + .into(); + Some(val) + } else { + unreachable!() + } + }, + )))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "float".into(), + simple_name: "float".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }], + ret: float, + vars: var_map.clone(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new( + |ctx, _, fun, args| { + let int32 = ctx.primitives.int32; + let int64 = ctx.primitives.int64; + let boolean = ctx.primitives.bool; + let float = ctx.primitives.float; + let arg_ty = fun.0.args[0].ty; + let arg = args[0].1; + if ctx.unifier.unioned(arg_ty, boolean) + || ctx.unifier.unioned(arg_ty, int32) + || ctx.unifier.unioned(arg_ty, int64) + { + let arg = args[0].1.into_int_value(); + let val = ctx + .builder + .build_signed_int_to_float(arg, ctx.ctx.f64_type(), "sitofp") + .into(); + Some(val) + } else if ctx.unifier.unioned(arg_ty, float) { + Some(arg) + } else { + unreachable!() + } + }, + )))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "round".into(), + simple_name: "round".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }], + ret: int32, + vars: Default::default(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { + let arg = args[0].1; + let round_intrinsic = + ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| { + let float = ctx.ctx.f64_type(); + let fn_type = float.fn_type(&[float.into()], false); + ctx.module.add_function("llvm.round.f64", fn_type, None) + }); + let val = ctx + .builder + .build_call(round_intrinsic, &[arg], "round") + .try_as_basic_value() + .left() + .unwrap(); + Some( + ctx.builder + .build_float_to_signed_int( + val.into_float_value(), + ctx.ctx.i32_type(), + "fptosi", + ) + .into(), + ) + })))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "round64".into(), + simple_name: "round64".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }], + ret: int64, + vars: Default::default(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { + let arg = args[0].1; + let round_intrinsic = + ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| { + let float = ctx.ctx.f64_type(); + let fn_type = float.fn_type(&[float.into()], false); + ctx.module.add_function("llvm.round.f64", fn_type, None) + }); + let val = ctx + .builder + .build_call(round_intrinsic, &[arg], "round") + .try_as_basic_value() + .left() + .unwrap(); + Some( + ctx.builder + .build_float_to_signed_int( + val.into_float_value(), + ctx.ctx.i64_type(), + "fptosi", + ) + .into(), + ) + })))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "range".into(), + simple_name: "range".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![ + FuncArg { name: "start".into(), ty: int32, default_value: None }, + FuncArg { + name: "stop".into(), + ty: int32, + // placeholder + default_value: Some(SymbolValue::I32(0)), + }, + FuncArg { + name: "step".into(), + ty: int32, + default_value: Some(SymbolValue::I32(1)), + }, + ], + ret: range, + vars: Default::default(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { + let mut start = None; + let mut stop = None; + let mut step = None; + let int32 = ctx.ctx.i32_type(); + let zero = int32.const_zero(); + for (i, arg) in args.iter().enumerate() { + if arg.0 == Some("start".into()) { + start = Some(arg.1); + } else if arg.0 == Some("stop".into()) { + stop = Some(arg.1); + } else if arg.0 == Some("step".into()) { + step = Some(arg.1); + } else if i == 0 { + start = Some(arg.1); + } else if i == 1 { + stop = Some(arg.1); + } else if i == 2 { + step = Some(arg.1); + } + } + // TODO: error when step == 0 + let step = step.unwrap_or_else(|| int32.const_int(1, false).into()); + let stop = stop.unwrap_or_else(|| { + let v = start.unwrap(); + start = None; + v + }); + let start = start.unwrap_or_else(|| int32.const_zero().into()); + let ty = int32.array_type(3); + let ptr = ctx.builder.build_alloca(ty, "range"); + unsafe { + let a = ctx.builder.build_in_bounds_gep(ptr, &[zero, zero], "start"); + let b = ctx.builder.build_in_bounds_gep( + ptr, + &[zero, int32.const_int(1, false)], + "end", + ); + let c = ctx.builder.build_in_bounds_gep( + ptr, + &[zero, int32.const_int(2, false)], + "step", + ); + ctx.builder.build_store(a, start); + ctx.builder.build_store(b, stop); + ctx.builder.build_store(c, step); + } + Some(ptr.into()) + })))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "str".into(), + simple_name: "str".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: string, default_value: None }], + ret: string, + vars: Default::default(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new(|_, _, _, args| { + Some(args[0].1) + })))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "bool".into(), + simple_name: "bool".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }], + ret: primitives.0.bool, + vars: var_map, + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new( + |ctx, _, fun, args| { + let int32 = ctx.primitives.int32; + let int64 = ctx.primitives.int64; + let float = ctx.primitives.float; + let boolean = ctx.primitives.bool; + let arg_ty = fun.0.args[0].ty; + let arg = args[0].1; + if ctx.unifier.unioned(arg_ty, boolean) { + Some(arg) + } else if ctx.unifier.unioned(arg_ty, int32) { + Some(ctx.builder.build_int_compare( + IntPredicate::NE, + ctx.ctx.i32_type().const_zero(), + arg.into_int_value(), + "bool", + ).into()) + } else if ctx.unifier.unioned(arg_ty, int64) { + Some(ctx.builder.build_int_compare( + IntPredicate::NE, + ctx.ctx.i64_type().const_zero(), + arg.into_int_value(), + "bool", + ).into()) + } else if ctx.unifier.unioned(arg_ty, float) { + let val = ctx.builder. + build_float_compare( + // UEQ as bool(nan) is True + FloatPredicate::UEQ, + arg.into_float_value(), + ctx.ctx.f64_type().const_zero(), + "bool" + ).into(); + Some(val) + } else { + unreachable!() + } + }, + )))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "floor".into(), + simple_name: "floor".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }], + ret: int32, + vars: Default::default(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { + let arg = args[0].1; + let floor_intrinsic = + ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| { + let float = ctx.ctx.f64_type(); + let fn_type = float.fn_type(&[float.into()], false); + ctx.module.add_function("llvm.floor.f64", fn_type, None) + }); + let val = ctx + .builder + .build_call(floor_intrinsic, &[arg], "floor") + .try_as_basic_value() + .left() + .unwrap(); + Some( + ctx.builder + .build_float_to_signed_int( + val.into_float_value(), + ctx.ctx.i32_type(), + "fptosi", + ) + .into(), + ) + })))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "floor64".into(), + simple_name: "floor64".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }], + ret: int64, + vars: Default::default(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { + let arg = args[0].1; + let floor_intrinsic = + ctx.module.get_function("llvm.floor.f64").unwrap_or_else(|| { + let float = ctx.ctx.f64_type(); + let fn_type = float.fn_type(&[float.into()], false); + ctx.module.add_function("llvm.floor.f64", fn_type, None) + }); + let val = ctx + .builder + .build_call(floor_intrinsic, &[arg], "floor") + .try_as_basic_value() + .left() + .unwrap(); + Some( + ctx.builder + .build_float_to_signed_int( + val.into_float_value(), + ctx.ctx.i64_type(), + "fptosi", + ) + .into(), + ) + })))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "ceil".into(), + simple_name: "ceil".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }], + ret: int32, + vars: Default::default(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { + let arg = args[0].1; + let ceil_intrinsic = + ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| { + let float = ctx.ctx.f64_type(); + let fn_type = float.fn_type(&[float.into()], false); + ctx.module.add_function("llvm.ceil.f64", fn_type, None) + }); + let val = ctx + .builder + .build_call(ceil_intrinsic, &[arg], "ceil") + .try_as_basic_value() + .left() + .unwrap(); + Some( + ctx.builder + .build_float_to_signed_int( + val.into_float_value(), + ctx.ctx.i32_type(), + "fptosi", + ) + .into(), + ) + })))), + })), + Arc::new(RwLock::new(TopLevelDef::Function { + name: "ceil64".into(), + simple_name: "ceil64".into(), + signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }], + ret: int64, + vars: Default::default(), + }))), + var_id: Default::default(), + instance_to_symbol: Default::default(), + instance_to_stmt: Default::default(), + resolver: None, + codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { + let arg = args[0].1; + let ceil_intrinsic = + ctx.module.get_function("llvm.ceil.f64").unwrap_or_else(|| { + let float = ctx.ctx.f64_type(); + let fn_type = float.fn_type(&[float.into()], false); + ctx.module.add_function("llvm.ceil.f64", fn_type, None) + }); + let val = ctx + .builder + .build_call(ceil_intrinsic, &[arg], "ceil") + .try_as_basic_value() + .left() + .unwrap(); + Some( + ctx.builder + .build_float_to_signed_int( + val.into_float_value(), + ctx.ctx.i64_type(), + "fptosi", + ) + .into(), + ) + })))), + })), + ]; + let ast_list: Vec>> = + (0..top_level_def_list.len()).map(|_| None).collect(); + ( + izip!(top_level_def_list, ast_list).collect_vec(), + &[ + "int32", + "int64", + "float", + "round", + "round64", + "range", + "str", + "bool", + "floor", + "floor64", + "ceil", + "ceil64" + ] + ) +} \ No newline at end of file diff --git a/nac3core/src/toplevel/composer.rs b/nac3core/src/toplevel/composer.rs index 137f1871e..c5367845e 100644 --- a/nac3core/src/toplevel/composer.rs +++ b/nac3core/src/toplevel/composer.rs @@ -1,10 +1,8 @@ use std::cell::RefCell; use nac3parser::ast::fold::Fold; -use inkwell::{FloatPredicate, IntPredicate}; use crate::{ - symbol_resolver::SymbolValue, typecheck::type_inferencer::{FunctionData, Inferencer}, codegen::expr::get_subst_key, }; @@ -42,413 +40,7 @@ impl TopLevelComposer { builtins: Vec<(StrRef, FunSignature, Arc)>, ) -> (Self, HashMap, HashMap) { let mut primitives = Self::make_primitives(); - - let int32 = primitives.0.int32; - let int64 = primitives.0.int64; - let float = primitives.0.float; - let boolean = primitives.0.bool; - let range = primitives.0.range; - let string = primitives.0.str; - let num_ty = primitives.1.get_fresh_var_with_range(&[int32, int64, float, boolean]); - let var_map: HashMap<_, _> = vec![(num_ty.1, num_ty.0)].into_iter().collect(); - - let mut definition_ast_list = { - let top_level_def_list = vec![ - Arc::new(RwLock::new(Self::make_top_level_class_def( - 0, - None, - "int32".into(), - None, - ))), - Arc::new(RwLock::new(Self::make_top_level_class_def( - 1, - None, - "int64".into(), - None, - ))), - Arc::new(RwLock::new(Self::make_top_level_class_def( - 2, - None, - "float".into(), - None, - ))), - Arc::new(RwLock::new(Self::make_top_level_class_def(3, None, "bool".into(), None))), - Arc::new(RwLock::new(Self::make_top_level_class_def(4, None, "none".into(), None))), - Arc::new(RwLock::new(Self::make_top_level_class_def( - 5, - None, - "range".into(), - None, - ))), - Arc::new(RwLock::new(Self::make_top_level_class_def(6, None, "str".into(), None))), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "int32".into(), - simple_name: "int32".into(), - signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { - args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }], - ret: int32, - vars: var_map.clone(), - }))), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new( - |ctx, _, fun, args| { - let int32 = ctx.primitives.int32; - let int64 = ctx.primitives.int64; - let float = ctx.primitives.float; - let boolean = ctx.primitives.bool; - let arg_ty = fun.0.args[0].ty; - let arg = args[0].1; - if ctx.unifier.unioned(arg_ty, boolean) { - Some( - ctx.builder - .build_int_s_extend( - arg.into_int_value(), - ctx.ctx.i32_type(), - "sext", - ) - .into(), - ) - } else if ctx.unifier.unioned(arg_ty, int32) { - Some(arg) - } else if ctx.unifier.unioned(arg_ty, int64) { - Some( - ctx.builder - .build_int_truncate( - arg.into_int_value(), - ctx.ctx.i32_type(), - "trunc", - ) - .into(), - ) - } else if ctx.unifier.unioned(arg_ty, float) { - let val = ctx - .builder - .build_float_to_signed_int( - arg.into_float_value(), - ctx.ctx.i32_type(), - "fptosi", - ) - .into(); - Some(val) - } else { - unreachable!() - } - }, - )))), - })), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "int64".into(), - simple_name: "int64".into(), - signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { - args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }], - ret: int64, - vars: var_map.clone(), - }))), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new( - |ctx, _, fun, args| { - let int32 = ctx.primitives.int32; - let int64 = ctx.primitives.int64; - let float = ctx.primitives.float; - let boolean = ctx.primitives.bool; - let arg_ty = fun.0.args[0].ty; - let arg = args[0].1; - if ctx.unifier.unioned(arg_ty, boolean) - || ctx.unifier.unioned(arg_ty, int32) - { - Some( - ctx.builder - .build_int_s_extend( - arg.into_int_value(), - ctx.ctx.i64_type(), - "sext", - ) - .into(), - ) - } else if ctx.unifier.unioned(arg_ty, int64) { - Some(arg) - } else if ctx.unifier.unioned(arg_ty, float) { - let val = ctx - .builder - .build_float_to_signed_int( - arg.into_float_value(), - ctx.ctx.i64_type(), - "fptosi", - ) - .into(); - Some(val) - } else { - unreachable!() - } - }, - )))), - })), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "float".into(), - simple_name: "float".into(), - signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { - args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }], - ret: float, - vars: var_map.clone(), - }))), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new( - |ctx, _, fun, args| { - let int32 = ctx.primitives.int32; - let int64 = ctx.primitives.int64; - let boolean = ctx.primitives.bool; - let float = ctx.primitives.float; - let arg_ty = fun.0.args[0].ty; - let arg = args[0].1; - if ctx.unifier.unioned(arg_ty, boolean) - || ctx.unifier.unioned(arg_ty, int32) - || ctx.unifier.unioned(arg_ty, int64) - { - let arg = args[0].1.into_int_value(); - let val = ctx - .builder - .build_signed_int_to_float(arg, ctx.ctx.f64_type(), "sitofp") - .into(); - Some(val) - } else if ctx.unifier.unioned(arg_ty, float) { - Some(arg) - } else { - unreachable!() - } - }, - )))), - })), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "round".into(), - simple_name: "round".into(), - signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { - args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }], - ret: int32, - vars: Default::default(), - }))), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { - let arg = args[0].1; - let round_intrinsic = - ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| { - let float = ctx.ctx.f64_type(); - let fn_type = float.fn_type(&[float.into()], false); - ctx.module.add_function("llvm.round.f64", fn_type, None) - }); - let val = ctx - .builder - .build_call(round_intrinsic, &[arg], "round") - .try_as_basic_value() - .left() - .unwrap(); - Some( - ctx.builder - .build_float_to_signed_int( - val.into_float_value(), - ctx.ctx.i32_type(), - "fptosi", - ) - .into(), - ) - })))), - })), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "round64".into(), - simple_name: "round64".into(), - signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { - args: vec![FuncArg { name: "_".into(), ty: float, default_value: None }], - ret: int64, - vars: Default::default(), - }))), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { - let arg = args[0].1; - let round_intrinsic = - ctx.module.get_function("llvm.round.f64").unwrap_or_else(|| { - let float = ctx.ctx.f64_type(); - let fn_type = float.fn_type(&[float.into()], false); - ctx.module.add_function("llvm.round.f64", fn_type, None) - }); - let val = ctx - .builder - .build_call(round_intrinsic, &[arg], "round") - .try_as_basic_value() - .left() - .unwrap(); - Some( - ctx.builder - .build_float_to_signed_int( - val.into_float_value(), - ctx.ctx.i64_type(), - "fptosi", - ) - .into(), - ) - })))), - })), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "range".into(), - simple_name: "range".into(), - signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { - args: vec![ - FuncArg { name: "start".into(), ty: int32, default_value: None }, - FuncArg { - name: "stop".into(), - ty: int32, - // placeholder - default_value: Some(SymbolValue::I32(0)), - }, - FuncArg { - name: "step".into(), - ty: int32, - default_value: Some(SymbolValue::I32(1)), - }, - ], - ret: range, - vars: Default::default(), - }))), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new(|ctx, _, _, args| { - let mut start = None; - let mut stop = None; - let mut step = None; - let int32 = ctx.ctx.i32_type(); - let zero = int32.const_zero(); - for (i, arg) in args.iter().enumerate() { - if arg.0 == Some("start".into()) { - start = Some(arg.1); - } else if arg.0 == Some("stop".into()) { - stop = Some(arg.1); - } else if arg.0 == Some("step".into()) { - step = Some(arg.1); - } else if i == 0 { - start = Some(arg.1); - } else if i == 1 { - stop = Some(arg.1); - } else if i == 2 { - step = Some(arg.1); - } - } - // TODO: error when step == 0 - let step = step.unwrap_or_else(|| int32.const_int(1, false).into()); - let stop = stop.unwrap_or_else(|| { - let v = start.unwrap(); - start = None; - v - }); - let start = start.unwrap_or_else(|| int32.const_zero().into()); - let ty = int32.array_type(3); - let ptr = ctx.builder.build_alloca(ty, "range"); - unsafe { - let a = ctx.builder.build_in_bounds_gep(ptr, &[zero, zero], "start"); - let b = ctx.builder.build_in_bounds_gep( - ptr, - &[zero, int32.const_int(1, false)], - "end", - ); - let c = ctx.builder.build_in_bounds_gep( - ptr, - &[zero, int32.const_int(2, false)], - "step", - ); - ctx.builder.build_store(a, start); - ctx.builder.build_store(b, stop); - ctx.builder.build_store(c, step); - } - Some(ptr.into()) - })))), - })), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "str".into(), - simple_name: "str".into(), - signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { - args: vec![FuncArg { name: "_".into(), ty: string, default_value: None }], - ret: string, - vars: Default::default(), - }))), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new(|_, _, _, args| { - Some(args[0].1) - })))), - })), - Arc::new(RwLock::new(TopLevelDef::Function { - name: "bool".into(), - simple_name: "bool".into(), - signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { - args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }], - ret: primitives.0.bool, - vars: var_map, - }))), - var_id: Default::default(), - instance_to_symbol: Default::default(), - instance_to_stmt: Default::default(), - resolver: None, - codegen_callback: Some(Arc::new(GenCall::new(Box::new( - |ctx, _, fun, args| { - let int32 = ctx.primitives.int32; - let int64 = ctx.primitives.int64; - let float = ctx.primitives.float; - let boolean = ctx.primitives.bool; - let arg_ty = fun.0.args[0].ty; - let arg = args[0].1; - if ctx.unifier.unioned(arg_ty, boolean) { - Some(arg) - } else if ctx.unifier.unioned(arg_ty, int32) { - Some(ctx.builder.build_int_compare( - IntPredicate::NE, - ctx.ctx.i32_type().const_zero(), - arg.into_int_value(), - "bool", - ).into()) - } else if ctx.unifier.unioned(arg_ty, int64) { - Some(ctx.builder.build_int_compare( - IntPredicate::NE, - ctx.ctx.i64_type().const_zero(), - arg.into_int_value(), - "bool", - ).into()) - } else if ctx.unifier.unioned(arg_ty, float) { - let val = ctx.builder. - build_float_compare( - // UEQ as bool(nan) is True - FloatPredicate::UEQ, - arg.into_float_value(), - ctx.ctx.f64_type().const_zero(), - "bool" - ).into(); - Some(val) - } else { - unreachable!() - } - }, - )))), - })), - ]; - let ast_list: Vec>> = - (0..top_level_def_list.len()).map(|_| None).collect(); - izip!(top_level_def_list, ast_list).collect_vec() - }; + let (mut definition_ast_list, builtin_name_list) = builtins::get_built_ins(&mut primitives); let primitives_ty = primitives.0; let mut unifier = primitives.1; let mut keyword_list: HashSet = HashSet::from_iter(vec![ @@ -474,9 +66,7 @@ impl TopLevelComposer { let mut built_in_id: HashMap = Default::default(); let mut built_in_ty: HashMap = Default::default(); - for (id, name) in - ["int32", "int64", "float", "round", "round64", "range", "str", "bool"].iter().rev().enumerate() - { + for (id, name) in builtin_name_list.iter().rev().enumerate() { let name = (**name).into(); let id = definition_ast_list.len() - id - 1; let def = definition_ast_list[id].0.read(); diff --git a/nac3core/src/toplevel/mod.rs b/nac3core/src/toplevel/mod.rs index bcf1e6263..4a8cbb074 100644 --- a/nac3core/src/toplevel/mod.rs +++ b/nac3core/src/toplevel/mod.rs @@ -24,6 +24,7 @@ pub struct DefinitionId(pub usize); pub mod composer; pub mod helper; +pub mod builtins; pub mod type_annotation; use composer::*; use type_annotation::*;