Array assignment
This commit is contained in:
parent
c119a077d6
commit
3af1535515
@ -17,3 +17,4 @@ The Elysium programming language.
|
||||
- [ ] Memory allocation, Heap allocator
|
||||
- [ ] Garbage collector
|
||||
- [ ] Support for wasm64
|
||||
- [ ] Imported functions (from JS)
|
||||
|
122
backend_wat.go
122
backend_wat.go
@ -8,9 +8,12 @@ import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const COMPILE_OPTION_NO_BOUNDS_CHECK = "no_bounds_check"
|
||||
|
||||
type Compiler struct {
|
||||
Files []*ParsedFile
|
||||
Wasm64 bool
|
||||
Files []*ParsedFile
|
||||
Wasm64 bool
|
||||
CompileOptions map[string]string
|
||||
|
||||
CurrentBlock *Block
|
||||
CurrentFunction *ParsedFunction
|
||||
@ -58,7 +61,7 @@ func getTypeCast(primitive PrimitiveType) string {
|
||||
case Primitive_U16:
|
||||
return "i32.const 65535\ni32.and\n"
|
||||
case Primitive_Bool:
|
||||
return "i32.const 1\ni32.and\n"
|
||||
return "i32.const 0\ni32.ne\n"
|
||||
}
|
||||
|
||||
return ""
|
||||
@ -222,7 +225,78 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
||||
local := strconv.Itoa(getLocal(c.CurrentBlock, ref.Variable).Index)
|
||||
return exprWAT + "local.tee $" + local + "\n", nil
|
||||
case Expression_ArrayAccess:
|
||||
panic("TODO") // TODO
|
||||
array := lhs.Value.(ArrayAccessExpression)
|
||||
|
||||
localArray := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType(), Position: unknownPosition()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localArray)
|
||||
|
||||
localIndex := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType(), Position: unknownPosition()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localIndex)
|
||||
|
||||
localElement := Local{Name: "", Type: *assignment.Value.ValueType, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
|
||||
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localElement)
|
||||
|
||||
arrayWAT, err := c.compileExpressionWAT(array.Array)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
arrayWAT += "local.set $" + strconv.Itoa(localArray.Index) + "\n"
|
||||
|
||||
indexWAT, err := c.compileExpressionWAT(array.Index)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !c.Wasm64 {
|
||||
cast, err := castPrimitiveWAT(Primitive_I64, Primitive_I32)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
indexWAT += cast
|
||||
}
|
||||
|
||||
indexWAT += "local.set $" + strconv.Itoa(localIndex.Index) + "\n"
|
||||
|
||||
wat := arrayWAT + indexWAT
|
||||
|
||||
if _, ok := c.CompileOptions[COMPILE_OPTION_NO_BOUNDS_CHECK]; !ok {
|
||||
// Error if index < 0
|
||||
wat += "block\n"
|
||||
wat += "local.get $" + strconv.Itoa(localIndex.Index) + "\n"
|
||||
wat += c.getAddressWATType() + ".const 0\n"
|
||||
wat += c.getAddressWATType() + ".ge_s\n"
|
||||
wat += "br_if 0\n"
|
||||
wat += "call $__builtin_panic\n"
|
||||
wat += "end\n"
|
||||
|
||||
// Error if index >= array length
|
||||
wat += "block\n"
|
||||
wat += "local.get $" + strconv.Itoa(localIndex.Index) + "\n"
|
||||
wat += "local.get $" + strconv.Itoa(localArray.Index) + "\n"
|
||||
wat += "i32.load\n" // Load array length
|
||||
wat += c.getAddressWATType() + ".lt_s\n"
|
||||
wat += "br_if 0\n"
|
||||
wat += "call $__builtin_panic\n"
|
||||
wat += "end\n"
|
||||
}
|
||||
|
||||
elementType := array.Array.ValueType.Value.(ArrayType).ElementType
|
||||
wat += "local.get $" + strconv.Itoa(localIndex.Index) + "\n"
|
||||
wat += c.getAddressWATType() + ".const " + strconv.Itoa(c.getTypeSizeBytes(elementType)) + "\n"
|
||||
wat += c.getAddressWATType() + ".mul\n"
|
||||
wat += "local.get $" + strconv.Itoa(localArray.Index) + "\n"
|
||||
wat += c.getAddressWATType() + ".add\n"
|
||||
wat += c.getAddressWATType() + ".const 4\n" // first 4 bytes = length
|
||||
wat += c.getAddressWATType() + ".add\n"
|
||||
|
||||
wat += exprWAT
|
||||
wat += "local.tee $" + strconv.Itoa(localElement.Index) + "\n"
|
||||
wat += c.getWATType(elementType) + ".store\n" // TODO: use load8/load16(_s/u) for smaller types
|
||||
wat += "local.get $" + strconv.Itoa(localElement.Index) + "\n"
|
||||
|
||||
return wat, nil
|
||||
case Expression_RawMemoryReference:
|
||||
raw := lhs.Value.(RawMemoryReferenceExpression)
|
||||
|
||||
@ -240,9 +314,9 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
|
||||
|
||||
// TODO: should leave a copy of the stored value on the stack
|
||||
return addrWAT + exprWAT +
|
||||
"local.tee " + strconv.Itoa(local.Index) + "\n" +
|
||||
"local.tee $" + strconv.Itoa(local.Index) + "\n" +
|
||||
c.getWATType(raw.Type) + ".store\n" +
|
||||
"local.get " + strconv.Itoa(local.Index) + "\n", nil
|
||||
"local.get $" + strconv.Itoa(local.Index) + "\n", nil
|
||||
}
|
||||
|
||||
panic("assignment expr not implemented")
|
||||
@ -555,24 +629,26 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (string, error) {
|
||||
|
||||
wat := arrayWAT + indexWAT
|
||||
|
||||
// Error if index <= 0
|
||||
wat += "block\n"
|
||||
wat += "local.get $" + strconv.Itoa(localIndex.Index) + "\n"
|
||||
wat += c.getAddressWATType() + ".const 0\n"
|
||||
wat += c.getAddressWATType() + ".gt_s\n"
|
||||
wat += "br_if 0\n"
|
||||
wat += "call $__builtin_panic\n"
|
||||
wat += "end\n"
|
||||
if _, ok := c.CompileOptions[COMPILE_OPTION_NO_BOUNDS_CHECK]; !ok {
|
||||
// Error if index < 0
|
||||
wat += "block\n"
|
||||
wat += "local.get $" + strconv.Itoa(localIndex.Index) + "\n"
|
||||
wat += c.getAddressWATType() + ".const 0\n"
|
||||
wat += c.getAddressWATType() + ".ge_s\n"
|
||||
wat += "br_if 0\n"
|
||||
wat += "call $__builtin_panic\n"
|
||||
wat += "end\n"
|
||||
|
||||
// Error if index >= array length
|
||||
wat += "block\n"
|
||||
wat += "local.get $" + strconv.Itoa(localIndex.Index) + "\n"
|
||||
wat += "local.get $" + strconv.Itoa(localArray.Index) + "\n"
|
||||
wat += "i32.load\n" // Load array length
|
||||
wat += c.getAddressWATType() + ".lt_s\n"
|
||||
wat += "br_if 0\n"
|
||||
wat += "call $__builtin_panic\n"
|
||||
wat += "end\n"
|
||||
// Error if index >= array length
|
||||
wat += "block\n"
|
||||
wat += "local.get $" + strconv.Itoa(localIndex.Index) + "\n"
|
||||
wat += "local.get $" + strconv.Itoa(localArray.Index) + "\n"
|
||||
wat += "i32.load\n" // Load array length
|
||||
wat += c.getAddressWATType() + ".lt_s\n"
|
||||
wat += "br_if 0\n"
|
||||
wat += "call $__builtin_panic\n"
|
||||
wat += "end\n"
|
||||
}
|
||||
|
||||
elementType := array.Array.ValueType.Value.(ArrayType).ElementType
|
||||
wat += "local.get $" + strconv.Itoa(localIndex.Index) + "\n"
|
||||
|
27
example/array.ely
Normal file
27
example/array.ely
Normal file
@ -0,0 +1,27 @@
|
||||
u64 array() {
|
||||
if(__builtin_memory_size() == 0u64) {
|
||||
__builtin_memory_grow(1u64);
|
||||
}
|
||||
|
||||
raw(u32, 0x0u64) = 1u32;
|
||||
raw(u64, 0x04u64) = 69u64;
|
||||
|
||||
u64[] array = raw(u64[], 0x0u64);
|
||||
array[0] = 1u64;
|
||||
array[1] = 2u64;
|
||||
|
||||
return array[0] + array[1];
|
||||
}
|
||||
|
||||
void array2() {
|
||||
u64[] array = raw(u64[], 0x0u64);
|
||||
array[0] = 1u64;
|
||||
}
|
||||
|
||||
u64[] arrayReturn() {
|
||||
if(__builtin_memory_size() == 0u64) {
|
||||
__builtin_memory_grow(1u64);
|
||||
}
|
||||
|
||||
return raw(u64[], 0x0u64);
|
||||
}
|
@ -38,7 +38,3 @@ u64 assign(u64 a) {
|
||||
a += 1u64;
|
||||
return raw(u64, a) += 2u64;
|
||||
}
|
||||
|
||||
u64 test() {
|
||||
return raw(u64[], 0x0u8)[0];
|
||||
}
|
||||
|
13
main.go
13
main.go
@ -90,6 +90,7 @@ func main() {
|
||||
generateWAT := flag.Bool("wat", false, "Generate WAT instead of WASM")
|
||||
wasm64 := flag.Bool("wasm64", false, "Use 64-bit memory (may not be supported in all browsers)")
|
||||
includeStdlib := flag.Bool("stdlib", true, "Include the standard library")
|
||||
compileOptions := flag.String("compileOptions", "", "The compile options (key=value,key2=value2,key3)")
|
||||
flag.Parse()
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
@ -169,7 +170,17 @@ func main() {
|
||||
|
||||
// log.Printf("Validated:\n%+#v\n\n", parsedFiles)
|
||||
|
||||
compiler := Compiler{Files: parsedFiles, Wasm64: *wasm64}
|
||||
compileOptionsMap := make(map[string]string, 0)
|
||||
for _, value := range strings.Split(*compileOptions, ",") {
|
||||
kv := strings.Split(value, "=")
|
||||
if len(kv) == 1 {
|
||||
compileOptionsMap[kv[0]] = ""
|
||||
} else {
|
||||
compileOptionsMap[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
|
||||
compiler := Compiler{Files: parsedFiles, Wasm64: *wasm64, CompileOptions: compileOptionsMap}
|
||||
wat, err := compiler.compile()
|
||||
if err != nil {
|
||||
if c, ok := err.(CompilerError); ok {
|
||||
|
@ -206,6 +206,7 @@ type ParsedFunction struct {
|
||||
ReturnType *Type
|
||||
Body *Block
|
||||
Locals []Local // All of the locals of the function, ordered by their index
|
||||
Position TokenPosition
|
||||
}
|
||||
|
||||
type Import struct {
|
||||
@ -1101,7 +1102,7 @@ func (p *Parser) expectFunction() (*ParsedFunction, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ParsedFunction{Name: name, Parameters: parameters, ReturnType: returnType, Body: body}, nil
|
||||
return &ParsedFunction{Name: name, Parameters: parameters, ReturnType: returnType, Body: body, Position: tok.Position}, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseFile() (*ParsedFile, error) {
|
||||
|
@ -25,12 +25,14 @@ var builtinFunctions map[string]*ParsedFunction = map[string]*ParsedFunction{
|
||||
FullName: "builtin." + BUILTIN_MEMORY_GROW,
|
||||
Parameters: []ParsedParameter{{Name: "memory", Type: Type{Type: Type_Primitive, Value: Primitive_U64, Position: unknownPosition()}}},
|
||||
ReturnType: &Type{Type: Type_Primitive, Value: Primitive_I64, Position: unknownPosition()},
|
||||
Position: unknownPosition(),
|
||||
},
|
||||
BUILTIN_MEMORY_SIZE: {
|
||||
Name: BUILTIN_MEMORY_SIZE,
|
||||
FullName: "builtin." + BUILTIN_MEMORY_SIZE,
|
||||
Parameters: []ParsedParameter{},
|
||||
ReturnType: &Type{Type: Type_Primitive, Value: Primitive_U64, Position: unknownPosition()},
|
||||
Position: unknownPosition(),
|
||||
},
|
||||
}
|
||||
|
||||
@ -640,7 +642,7 @@ func (v *Validator) validate() []error {
|
||||
function.FullName = fullFunctionName
|
||||
|
||||
if _, exists := v.AllFunctions[fullFunctionName]; exists {
|
||||
errors = append(errors, v.createError("duplicate function "+fullFunctionName, function.ReturnType.Position))
|
||||
errors = append(errors, v.createError("duplicate function "+fullFunctionName, function.Position))
|
||||
}
|
||||
|
||||
v.AllFunctions[fullFunctionName] = function
|
||||
|
Loading…
Reference in New Issue
Block a user