From 0c23c326ac1ba9fbb2cc51a64f8b930ba6975994 Mon Sep 17 00:00:00 2001 From: MrLetsplay Date: Sun, 27 Oct 2024 00:07:14 +0200 Subject: [PATCH] Builtin functions for memory.grow and memory.size --- backend_wat.go | 40 ++++++++++++++++++++++++++- lexer.go | 4 +++ stdlib/alloc.ely | 11 +++++++- validator.go | 70 +++++++++++++++++++++++++++++++++--------------- 4 files changed, 102 insertions(+), 23 deletions(-) diff --git a/backend_wat.go b/backend_wat.go index 48ecc29..15d9063 100644 --- a/backend_wat.go +++ b/backend_wat.go @@ -385,7 +385,45 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (string, error) { } } - return wat + "call $" + fc.Function + "\n", nil + switch fc.Function { + case BUILTIN_MEMORY_GROW: + if !c.Wasm64 { + cast, err := castPrimitiveWAT(Primitive_U64, Primitive_U32) + if err != nil { + return "", err + } + + wat += cast + } + + wat += "memory.grow\n" + + if !c.Wasm64 { + cast, err := castPrimitiveWAT(Primitive_I32, Primitive_I64) + if err != nil { + return "", err + } + + wat += cast + } + + return wat, nil + case BUILTIN_MEMORY_SIZE: + wat += "memory.size\n" + + if !c.Wasm64 { + cast, err := castPrimitiveWAT(Primitive_U32, Primitive_U64) + if err != nil { + return "", err + } + + wat += cast + } + + return wat, nil + default: + return wat + "call $" + fc.Function + "\n", nil + } case Expression_Unary: unary := expr.Value.(UnaryExpression) exprType := expr.ValueType.Value.(PrimitiveType) diff --git a/lexer.go b/lexer.go index 034caf5..00f040e 100644 --- a/lexer.go +++ b/lexer.go @@ -113,6 +113,10 @@ type Lexer struct { Position uint64 } +func unknownPosition() TokenPosition { + return TokenPosition{SourceFile: "", Position: 0} +} + func (l *Lexer) error(message string) error { return CompilerError{Position: TokenPosition{SourceFile: l.SourceFile, Position: l.LastTokenPosition}, Message: message} } diff --git a/stdlib/alloc.ely b/stdlib/alloc.ely index 57b62ae..80096ef 100644 --- a/stdlib/alloc.ely +++ b/stdlib/alloc.ely @@ -9,5 +9,14 @@ void free(u64 address) { } u64 growMemory(u64 numPages) { - return 0u64; + i64 value = __builtin_memory_grow(numPages); + if(value == -1) { + return 0u64; + } + + return __builtin_memory_size(); +} + +u64 memorySize() { + return __builtin_memory_size(); } diff --git a/validator.go b/validator.go index 960efb8..d501030 100644 --- a/validator.go +++ b/validator.go @@ -14,6 +14,26 @@ type Validator struct { CurrentFunction *ParsedFunction } +const ( + BUILTIN_MEMORY_GROW = "__builtin_memory_grow" + BUILTIN_MEMORY_SIZE = "__builtin_memory_size" +) + +var builtinFunctions map[string]*ParsedFunction = map[string]*ParsedFunction{ + BUILTIN_MEMORY_GROW: { + Name: BUILTIN_MEMORY_GROW, + 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()}, + }, + BUILTIN_MEMORY_SIZE: { + Name: BUILTIN_MEMORY_SIZE, + FullName: "builtin." + BUILTIN_MEMORY_SIZE, + Parameters: []ParsedParameter{}, + ReturnType: &Type{Type: Type_Primitive, Value: Primitive_U64, Position: unknownPosition()}, + }, +} + func isSameType(a Type, b Type) bool { if a.Type != b.Type { return false @@ -294,10 +314,13 @@ func (v *Validator) validatePotentiallyVoidExpression(expr *Expression) []error case Expression_FunctionCall: fc := expr.Value.(FunctionCallExpression) - calledFunc, ok := v.AllFunctions[fc.Function] + calledFunc, ok := builtinFunctions[fc.Function] if !ok { - errors = append(errors, v.createError("call to undefined function '"+fc.Function+"'", expr.Position)) - return errors + calledFunc, ok = v.AllFunctions[fc.Function] + if !ok { + errors = append(errors, v.createError("call to undefined function '"+fc.Function+"'", expr.Position)) + return errors + } } if fc.Parameters != nil { @@ -306,27 +329,32 @@ func (v *Validator) validatePotentiallyVoidExpression(expr *Expression) []error errors = append(errors, paramsErrors...) return errors } + } - params := []*Expression{fc.Parameters} - if fc.Parameters.Type == Expression_Tuple { - for i := 0; i < len(fc.Parameters.Value.(TupleExpression).Members); i++ { - params[i] = &fc.Parameters.Value.(TupleExpression).Members[i] - } + var params []*Expression + if fc.Parameters == nil { + params = []*Expression{} + } else if fc.Parameters.Type == Expression_Tuple { + params = make([]*Expression, len(fc.Parameters.Value.(TupleExpression).Members)) + for i := 0; i < len(fc.Parameters.Value.(TupleExpression).Members); i++ { + params[i] = &fc.Parameters.Value.(TupleExpression).Members[i] + } + } else { + params = []*Expression{fc.Parameters} + } + + if len(params) != len(calledFunc.Parameters) { + errors = append(errors, v.createError("wrong number of arguments in function call: expected "+strconv.Itoa(len(calledFunc.Parameters))+", got "+strconv.Itoa(len(params)), expr.Position)) + } + + for i := 0; i < min(len(params), len(calledFunc.Parameters)); i++ { + typeGiven := params[i] + typeExpected := calledFunc.Parameters[i] + if !isTypeExpandableTo(*typeGiven.ValueType, typeExpected.Type) { + errors = append(errors, v.createError("invalid type for parameter "+strconv.Itoa(i)+": expected "+typeExpected.Type.String()+", got "+typeGiven.ValueType.String(), expr.Position)) } - if len(params) != len(calledFunc.Parameters) { - errors = append(errors, v.createError("wrong number of arguments in function call: expected "+strconv.Itoa(len(calledFunc.Parameters))+", got "+strconv.Itoa(len(params)), expr.Position)) - } - - for i := 0; i < min(len(params), len(calledFunc.Parameters)); i++ { - typeGiven := params[i] - typeExpected := calledFunc.Parameters[i] - if !isTypeExpandableTo(*typeGiven.ValueType, typeExpected.Type) { - errors = append(errors, v.createError("invalid type for parameter "+strconv.Itoa(i), expr.Position)) - } - - expandExpressionToType(typeGiven, typeExpected.Type) - } + expandExpressionToType(typeGiven, typeExpected.Type) } expr.ValueType = calledFunc.ReturnType