forked from M-Labs/nac3
added array, WIP
This commit is contained in:
parent
858cc65daa
commit
814c3abf89
11
shell.nix
Normal file
11
shell.nix
Normal file
@ -0,0 +1,11 @@
|
||||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
in
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "nac3";
|
||||
buildInputs = [
|
||||
pkgs.libffi
|
||||
pkgs.libxml2
|
||||
pkgs.llvm_8
|
||||
];
|
||||
}
|
99
src/main.rs
99
src/main.rs
@ -223,6 +223,56 @@ impl<'ctx> CodeGen<'ctx> {
|
||||
ast::ExpressionType::Number { value: ast::Number::Float { value } } => {
|
||||
Ok(self.context.f64_type().const_float(*value).into())
|
||||
},
|
||||
ast::ExpressionType::List { elements } => {
|
||||
if elements.len() == 0 {
|
||||
return Err(self.compile_error(CompileErrorKind::Unsupported("Empty Array")));
|
||||
}
|
||||
let elements: CompileResult<Vec<_>> = elements.iter().map(|v| self.compile_expression(v)).collect();
|
||||
let elements = elements?;
|
||||
let ty = elements[0].get_type();
|
||||
for v in elements.iter() {
|
||||
if v.get_type() != ty {
|
||||
return Err(self.compile_error(CompileErrorKind::IncompatibleTypes));
|
||||
}
|
||||
}
|
||||
let len = self.context.i32_type().const_int(1 + elements.len() as u64, false);
|
||||
let real_len = self.context.i32_type().const_int(elements.len() as u64, false);
|
||||
let ptr = self.builder.build_array_alloca(ty, len, "tmparr");
|
||||
unsafe {
|
||||
let len_ptr = self.builder.build_in_bounds_gep(ptr,
|
||||
&[self.context.i32_type().const_int(0, false)], "len");
|
||||
self.builder.build_store(len_ptr, real_len);
|
||||
}
|
||||
for (i, v) in elements.iter().enumerate() {
|
||||
let ptr = unsafe {
|
||||
self.builder.build_in_bounds_gep(ptr,
|
||||
&[self.context.i32_type().const_int(1 + i as u64, false)],
|
||||
"gep")
|
||||
};
|
||||
self.builder.build_store(ptr, *v);
|
||||
}
|
||||
Ok(ptr.into())
|
||||
},
|
||||
ast::ExpressionType::Subscript { a, b } => {
|
||||
let a = self.compile_expression(a)?;
|
||||
let b = self.compile_expression(b)?;
|
||||
let a = match a.get_type() {
|
||||
types::BasicTypeEnum::PointerType(_) => a.into_pointer_value(),
|
||||
_ => return Err(self.compile_error(CompileErrorKind::IncompatibleTypes))
|
||||
};
|
||||
let b = match b.get_type() {
|
||||
types::BasicTypeEnum::IntType(_) => b.into_int_value().const_add(
|
||||
self.context.i32_type().const_int(1, false)
|
||||
),
|
||||
_ => return Err(self.compile_error(CompileErrorKind::IncompatibleTypes))
|
||||
};
|
||||
// TODO: add range check
|
||||
let ptr = unsafe {
|
||||
self.builder.build_in_bounds_gep(a,
|
||||
&[b], "gep")
|
||||
};
|
||||
Ok(self.builder.build_load(ptr, "load").into())
|
||||
},
|
||||
ast::ExpressionType::Identifier { name } => {
|
||||
match self.namespace.get(name) {
|
||||
Some(value) => Ok(self.builder.build_load(*value, name).into()),
|
||||
@ -425,18 +475,47 @@ impl<'ctx> CodeGen<'ctx> {
|
||||
match &statement.node {
|
||||
Assign { targets, value } => {
|
||||
let value = self.compile_expression(value)?;
|
||||
// TODO: Handle tuple
|
||||
for target in targets.iter() {
|
||||
self.set_source_location(target.location);
|
||||
if let ast::ExpressionType::Identifier { name } = &target.node {
|
||||
let builder = &self.builder;
|
||||
let target = self.namespace.entry(name.clone()).or_insert_with(
|
||||
|| builder.build_alloca(value.get_type(), name));
|
||||
if target.get_type() != value.get_type().ptr_type(inkwell::AddressSpace::Generic) {
|
||||
return Err(self.compile_error(CompileErrorKind::IncompatibleTypes));
|
||||
let value_typ = value.get_type().ptr_type(inkwell::AddressSpace::Generic);
|
||||
match &target.node {
|
||||
ast::ExpressionType::Identifier { name } => {
|
||||
let builder = &self.builder;
|
||||
let target = self.namespace.entry(name.clone()).or_insert_with(
|
||||
|| builder.build_alloca(value.get_type(), name));
|
||||
if target.get_type() != value_typ {
|
||||
return Err(self.compile_error(CompileErrorKind::IncompatibleTypes));
|
||||
}
|
||||
builder.build_store(*target, value);
|
||||
},
|
||||
ast::ExpressionType::Subscript {a, b} => {
|
||||
let a = self.compile_expression(a)?;
|
||||
let b = self.compile_expression(b)?;
|
||||
let a = match a.get_type() {
|
||||
types::BasicTypeEnum::PointerType(_) => a.into_pointer_value(),
|
||||
_ => return Err(self.compile_error(CompileErrorKind::IncompatibleTypes))
|
||||
};
|
||||
let b = match b.get_type() {
|
||||
types::BasicTypeEnum::IntType(_) => b.into_int_value().const_add(
|
||||
self.context.i32_type().const_int(1, false)
|
||||
),
|
||||
_ => return Err(self.compile_error(CompileErrorKind::IncompatibleTypes))
|
||||
};
|
||||
// TODO: range check
|
||||
let target = unsafe {
|
||||
self.builder.build_in_bounds_gep(a,
|
||||
&[b], "gep")
|
||||
};
|
||||
if target.get_type() != value_typ {
|
||||
return Err(self.compile_error(CompileErrorKind::IncompatibleTypes));
|
||||
}
|
||||
self.builder.build_store(target, value);
|
||||
},
|
||||
_ => {
|
||||
return Err(self.compile_error(CompileErrorKind::Unsupported(
|
||||
"assignment target must be an identifier")));
|
||||
}
|
||||
builder.build_store(*target, value);
|
||||
} else {
|
||||
return Err(self.compile_error(CompileErrorKind::Unsupported("assignment target must be an identifier")))
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -586,7 +665,7 @@ impl<'ctx> CodeGen<'ctx> {
|
||||
fn main() {
|
||||
Target::initialize_all(&InitializationConfig::default());
|
||||
|
||||
let program = match fs::read_to_string("test.py") {
|
||||
let program = match fs::read_to_string("test_arr.py") {
|
||||
Ok(program) => program,
|
||||
Err(err) => { println!("Cannot open input file: {}", err); return; }
|
||||
};
|
||||
|
9
test_arr.py
Normal file
9
test_arr.py
Normal file
@ -0,0 +1,9 @@
|
||||
def run() -> int32:
|
||||
arr = [1, 2]
|
||||
output(arr[0] + arr[1])
|
||||
|
||||
arr2 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
||||
arr2[output(1)][0] = 3
|
||||
arr3 = [arr, arr2[0], arr2[1], arr2[2]]
|
||||
output(arr3[0][0] + arr2[1][0] + arr2[2][0])
|
||||
return 0
|
Loading…
Reference in New Issue
Block a user