diff --git a/bin/jamlang.exe b/bin/jamlang.exe index e6d34a2..9f231d2 100644 Binary files a/bin/jamlang.exe and b/bin/jamlang.exe differ diff --git a/main.go b/main.go index 0d811a8..7551e02 100644 --- a/main.go +++ b/main.go @@ -93,53 +93,13 @@ func main() { } if args[0] == "math" { - resp, err := http.Get("https://raw.githubusercontent.com/Jamlee977/CustomLanguage/main/std/math.jam") - if err != nil { - fmt.Println(err) - os.Exit(0) - } - defer resp.Body.Close() - - if _, err := os.Stat("std"); os.IsNotExist(err) { - os.Mkdir("std", 0755) - } - - file, err := os.Create("std/" + args[0] + ".jam") - if err != nil { - fmt.Println(err) - os.Exit(0) - } - defer file.Close() - - _, err = io.Copy(file, resp.Body) - if err != nil { - fmt.Println(err) - os.Exit(0) - } + getLibrary("math") } else if args[0] == "random" { - resp, err := http.Get("https://raw.githubusercontent.com/Jamlee977/CustomLanguage/main/std/random.jam") - if err != nil { - fmt.Println(err) - os.Exit(0) - } - defer resp.Body.Close() - - if _, err := os.Stat("std"); os.IsNotExist(err) { - os.Mkdir("std", 0755) - } - - file, err := os.Create("std/" + args[0] + ".jam") - if err != nil { - fmt.Println(err) - os.Exit(0) - } - defer file.Close() - - _, err = io.Copy(file, resp.Body) - if err != nil { - fmt.Println(err) - os.Exit(0) - } + getLibrary("random") + } else if args[0] == "algorithm" { + getLibrary("algorithm") + } else if args[0] == "linkedlist" { + getLibrary("linkedlist") } else { fmt.Println("Unknown library") os.Exit(0) @@ -171,7 +131,6 @@ func main() { fmt.Println(err) os.Exit(0) } - } else if args[0] == "help" { fmt.Println("Usage: jamlang [options] [file]") fmt.Println("Options:") @@ -193,54 +152,14 @@ func main() { } if args[1] == "math" { - resp, err := http.Get("https://raw.githubusercontent.com/Jamlee977/CustomLanguage/main/std/math.jam") - if err != nil { - fmt.Println(err) - os.Exit(0) - } - defer resp.Body.Close() - - if _, err := os.Stat("std"); os.IsNotExist(err) { - os.Mkdir("std", 0755) - } - - file, err := os.Create("std/" + args[1] + ".jam") - if err != nil { - fmt.Println(err) - os.Exit(0) - } - defer file.Close() - - _, err = io.Copy(file, resp.Body) - if err != nil { - fmt.Println(err) - os.Exit(0) - } + getLibrary("math") } else if args[1] == "random" { - resp, err := http.Get("https://raw.githubusercontent.com/Jamlee977/CustomLanguage/main/std/random.jam") - if err != nil { - fmt.Println(err) - os.Exit(0) - } - defer resp.Body.Close() - - if _, err := os.Stat("std"); os.IsNotExist(err) { - os.Mkdir("std", 0755) - } - - file, err := os.Create("std/random.jam") - if err != nil { - fmt.Println(err) - os.Exit(0) - } - defer file.Close() - - _, err = io.Copy(file, resp.Body) - if err != nil { - fmt.Println(err) - os.Exit(0) - } - } else { + getLibrary("random") + } else if args[1] == "algorithm" { + getLibrary("algorithm") + } else if args[1] == "linkedlist" { + getLibrary("linkedlist") + }else { fmt.Println("Unknown library") os.Exit(0) } @@ -258,6 +177,33 @@ func main() { } } +func getLibrary(name string) { + link := fmt.Sprintf("https://raw.githubusercontent.com/Jamlie/CustomLanguage/main/std/%s.jam", name) + resp, err := http.Get(link) + if err != nil { + fmt.Println(err) + os.Exit(0) + } + defer resp.Body.Close() + + if _, err := os.Stat("std"); os.IsNotExist(err) { + os.Mkdir("std", 0755) + } + + file, err := os.Create("std/" + name + ".jam") + if err != nil { + fmt.Println(err) + os.Exit(0) + } + defer file.Close() + + _, err = io.Copy(file, resp.Body) + if err != nil { + fmt.Println(err) + os.Exit(0) + } +} + /* { class := ClassValue{ diff --git a/runtimelang/builtin.go b/runtimelang/builtin.go index 1b133fb..58327cb 100644 --- a/runtimelang/builtin.go +++ b/runtimelang/builtin.go @@ -1,272 +1,272 @@ package runtimelang import ( - "fmt" - "os" - "strconv" - "time" + "fmt" + "os" + "strconv" + "time" ) func jamlangPrintln(args []RuntimeValue, environment Environment) RuntimeValue { - for _, arg := range args { - fmt.Print(arg.Get(), " ") - } - fmt.Println() - return MakeNullValue() + for _, arg := range args { + fmt.Print(arg.Get()) + } + fmt.Println() + return MakeNullValue() } func jamlangPrint(args []RuntimeValue, environment Environment) RuntimeValue { - for _, arg := range args { - fmt.Print(arg.Get(), " ") - } - return MakeNullValue() + for _, arg := range args { + fmt.Print(arg.Get()) + } + return MakeNullValue() } func jamlangSleep(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 1 { - fmt.Println("sleep takes 1 argument") - os.Exit(0) - } - - if args[0].Type() != "number" { - fmt.Println("sleep takes a number - time in milliseconds") - os.Exit(0) - } - - time.Sleep(time.Duration(args[0].Get().(float64)) * time.Millisecond) - return MakeNullValue() + if len(args) != 1 { + fmt.Println("sleep takes 1 argument") + os.Exit(0) + } + + if args[0].Type() != "number" { + fmt.Println("sleep takes a number - time in milliseconds") + os.Exit(0) + } + + time.Sleep(time.Duration(args[0].Get().(float64)) * time.Millisecond) + return MakeNullValue() } func jamlangTypeof(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 1 { - fmt.Println("typeof takes 1 argument") - os.Exit(0) - } + if len(args) != 1 { + fmt.Println("typeof takes 1 argument") + os.Exit(0) + } - return MakeStringValue(string(args[0].Type())) + return MakeStringValue(string(args[0].Type())) } func jamlangExit(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 1 { - fmt.Println("exit takes 1 argument") - os.Exit(0) - } - - if args[0].Type() != "number" { - fmt.Println("exit takes a number - exit code") - os.Exit(0) - } - - os.Exit(int(args[0].Get().(float64))) - return MakeNullValue() + if len(args) != 1 { + fmt.Println("exit takes 1 argument") + os.Exit(0) + } + + if args[0].Type() != "number" { + fmt.Println("exit takes a number - exit code") + os.Exit(0) + } + + os.Exit(int(args[0].Get().(float64))) + return MakeNullValue() } func jamlangInput(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 1 { - fmt.Println("input takes 1 argument") - os.Exit(0) - } - - var input string - fmt.Scanln(&input) - return MakeStringValue(input) + if len(args) != 1 { + fmt.Println("input takes 1 argument") + os.Exit(0) + } + + var input string + fmt.Scanln(&input) + return MakeStringValue(input) } func jamlangLen(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 1 { - fmt.Println("len takes 1 argument") - os.Exit(0) - } - - if args[0].Type() == "array" { - goArray := ToGoArrayValue(args[0].(ArrayValue)) - return MakeNumberValue(float64(len(goArray))) - } else if args[0].Type() == "tuple" { - goTuple := ToGoTupleValue(args[0].(TupleValue)) - return MakeNumberValue(float64(len(goTuple))) - } else if args[0].Type() == "string" { - goString := ToGoStringValue(args[0].(StringValue)) - return MakeNumberValue(float64(len(goString))) - } else { - fmt.Println("len takes an array, tuple or string") - os.Exit(0) - return MakeNullValue() - } + if len(args) != 1 { + fmt.Println("len takes 1 argument") + os.Exit(0) + } + + if args[0].Type() == "array" { + goArray := ToGoArrayValue(args[0].(ArrayValue)) + return MakeNumberValue(float64(len(goArray))) + } else if args[0].Type() == "tuple" { + goTuple := ToGoTupleValue(args[0].(TupleValue)) + return MakeNumberValue(float64(len(goTuple))) + } else if args[0].Type() == "string" { + goString := ToGoStringValue(args[0].(StringValue)) + return MakeNumberValue(float64(len(goString))) + } else { + fmt.Println("len takes an array, tuple or string") + os.Exit(0) + return MakeNullValue() + } } func jamlangAppend(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 2 { - fmt.Println("append takes 2 arguments") - os.Exit(0) - } - - if args[0].Type() != "array" { - fmt.Println("append takes an array") - os.Exit(0) - } - - goArray := ToGoArrayValue(args[0].(ArrayValue)) - goArray = append(goArray, args[1]) - return MakeArrayValue(goArray) + if len(args) != 2 { + fmt.Println("append takes 2 arguments") + os.Exit(0) + } + + if args[0].Type() != "array" { + fmt.Println("append takes an array") + os.Exit(0) + } + + goArray := ToGoArrayValue(args[0].(ArrayValue)) + goArray = append(goArray, args[1]) + return MakeArrayValue(goArray) } func jamlangPop(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 1 { - fmt.Println("pop takes 1 argument") - os.Exit(0) - } - - if args[0].Type() != "array" { - fmt.Println("pop takes an array") - os.Exit(0) - } - - goArray := ToGoArrayValue(args[0].(ArrayValue)) - if len(goArray) == 0 { - fmt.Println("pop takes a non-empty array") - os.Exit(0) - } - - return MakeArrayValue(goArray[:len(goArray)-1]) + if len(args) != 1 { + fmt.Println("pop takes 1 argument") + os.Exit(0) + } + + if args[0].Type() != "array" { + fmt.Println("pop takes an array") + os.Exit(0) + } + + goArray := ToGoArrayValue(args[0].(ArrayValue)) + if len(goArray) == 0 { + fmt.Println("pop takes a non-empty array") + os.Exit(0) + } + + return MakeArrayValue(goArray[:len(goArray)-1]) } func jamlangSetArrayElement(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 3 { - fmt.Println("set takes 3 arguments") - os.Exit(0) - } - - if args[0].Type() != "array" { - fmt.Println("set takes an array") - os.Exit(0) - } - - goArray := ToGoArrayValue(args[0].(ArrayValue)) - index := int(ToGoNumberValue(args[1].(NumberValue))) - if index < 0 || index >= len(goArray) { - fmt.Println("set takes a valid index") - os.Exit(0) - } - - goArray[index] = args[2] - return MakeArrayValue(goArray) + if len(args) != 3 { + fmt.Println("set takes 3 arguments") + os.Exit(0) + } + + if args[0].Type() != "array" { + fmt.Println("set takes an array") + os.Exit(0) + } + + goArray := ToGoArrayValue(args[0].(ArrayValue)) + index := int(ToGoNumberValue(args[1].(NumberValue))) + if index < 0 || index >= len(goArray) { + fmt.Println("set takes a valid index") + os.Exit(0) + } + + goArray[index] = args[2] + return MakeArrayValue(goArray) } func jamlangCopy(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 1 { - fmt.Println("copy takes 1 argument") - os.Exit(0) - } - - if args[0].Type() == "array" { - goArray := ToGoArrayValue(args[0].(ArrayValue)) - goArrayCopy := make([]RuntimeValue, len(goArray)) - copy(goArrayCopy, goArray) - return MakeArrayValue(goArrayCopy) - } else if args[0].Type() == "tuple" { - goTuple := ToGoTupleValue(args[0].(TupleValue)) - goTupleCopy := make([]RuntimeValue, len(goTuple)) - copy(goTupleCopy, goTuple) - return MakeTupleValue(goTupleCopy) - } else { - fmt.Println("copy takes an array or tuple") - os.Exit(0) - return MakeNullValue() - } + if len(args) != 1 { + fmt.Println("copy takes 1 argument") + os.Exit(0) + } + + if args[0].Type() == "array" { + goArray := ToGoArrayValue(args[0].(ArrayValue)) + goArrayCopy := make([]RuntimeValue, len(goArray)) + copy(goArrayCopy, goArray) + return MakeArrayValue(goArrayCopy) + } else if args[0].Type() == "tuple" { + goTuple := ToGoTupleValue(args[0].(TupleValue)) + goTupleCopy := make([]RuntimeValue, len(goTuple)) + copy(goTupleCopy, goTuple) + return MakeTupleValue(goTupleCopy) + } else { + fmt.Println("copy takes an array or tuple") + os.Exit(0) + return MakeNullValue() + } } func jamlangTuple(args []RuntimeValue, environment Environment) RuntimeValue { - return MakeTupleValue(args) + return MakeTupleValue(args) } func jamlangToString(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 1 { - fmt.Println("string takes 1 argument") - os.Exit(0) - } + if len(args) != 1 { + fmt.Println("string takes 1 argument") + os.Exit(0) + } - return MakeStringValue(args[0].ToString()) + return MakeStringValue(args[0].ToString()) } func jamlangHex(args []RuntimeValue, environment Environment) RuntimeValue { - // takes a string value of a hexadecimally encoded number and returns a number value - if len(args) != 1 { - fmt.Println("hex takes 1 argument") - os.Exit(0) - } - - if args[0].Type() != "string" { - fmt.Println("hex takes a string") - os.Exit(0) - } - - hexString := args[0].ToString() - - hexInt, err := strconv.ParseInt(hexString, 16, 64) - if err != nil { - fmt.Println("hex takes a string") - os.Exit(0) - } - - return MakeNumberValue(float64(hexInt)) + // takes a string value of a hexadecimally encoded number and returns a number value + if len(args) != 1 { + fmt.Println("hex takes 1 argument") + os.Exit(0) + } + + if args[0].Type() != "string" { + fmt.Println("hex takes a string") + os.Exit(0) + } + + hexString := args[0].ToString() + + hexInt, err := strconv.ParseInt(hexString, 16, 64) + if err != nil { + fmt.Println("hex takes a string") + os.Exit(0) + } + + return MakeNumberValue(float64(hexInt)) } func jamlangCurrentTime(args []RuntimeValue, environment Environment) RuntimeValue { - return MakeNumberValue(float64(time.Now().UnixMicro())) + return MakeNumberValue(float64(time.Now().UnixMicro())) } func jamlangBitwiseNot(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 1 { - fmt.Println("bitwise not takes 1 argument") - os.Exit(0) - } + if len(args) != 1 { + fmt.Println("bitwise not takes 1 argument") + os.Exit(0) + } - if args[0].Type() != "number" { - fmt.Println("bitwise not takes a number") - os.Exit(0) - } + if args[0].Type() != "number" { + fmt.Println("bitwise not takes a number") + os.Exit(0) + } - return MakeNumberValue(float64(^int64(args[0].(NumberValue).Value))) + return MakeNumberValue(float64(^int64(args[0].(NumberValue).Value))) } func jamlangBitwiseAnd(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 2 { - fmt.Println("bitwise and takes 2 arguments") - os.Exit(0) - } + if len(args) != 2 { + fmt.Println("bitwise and takes 2 arguments") + os.Exit(0) + } - if args[0].Type() != "number" || args[1].Type() != "number" { - fmt.Println("bitwise and takes 2 numbers") - os.Exit(0) - } + if args[0].Type() != "number" || args[1].Type() != "number" { + fmt.Println("bitwise and takes 2 numbers") + os.Exit(0) + } - return MakeNumberValue(float64(int64(args[0].(NumberValue).Value) & int64(args[1].(NumberValue).Value))) + return MakeNumberValue(float64(int64(args[0].(NumberValue).Value) & int64(args[1].(NumberValue).Value))) } func jamlangBitwiseOr(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 2 { - fmt.Println("bitwise or takes 2 arguments") - os.Exit(0) - } + if len(args) != 2 { + fmt.Println("bitwise or takes 2 arguments") + os.Exit(0) + } - if args[0].Type() != "number" || args[1].Type() != "number" { - fmt.Println("bitwise or takes 2 numbers") - os.Exit(0) - } + if args[0].Type() != "number" || args[1].Type() != "number" { + fmt.Println("bitwise or takes 2 numbers") + os.Exit(0) + } - return MakeNumberValue(float64(int64(args[0].(NumberValue).Value) | int64(args[1].(NumberValue).Value))) + return MakeNumberValue(float64(int64(args[0].(NumberValue).Value) | int64(args[1].(NumberValue).Value))) } func jamlangBitwiseXor(args []RuntimeValue, environment Environment) RuntimeValue { - if len(args) != 2 { - fmt.Println("bitwise xor takes 2 arguments") - os.Exit(0) - } + if len(args) != 2 { + fmt.Println("bitwise xor takes 2 arguments") + os.Exit(0) + } - if args[0].Type() != "number" || args[1].Type() != "number" { - fmt.Println("bitwise xor takes 2 numbers") - os.Exit(0) - } + if args[0].Type() != "number" || args[1].Type() != "number" { + fmt.Println("bitwise xor takes 2 numbers") + os.Exit(0) + } - return MakeNumberValue(float64(int64(args[0].(NumberValue).Value) ^ int64(args[1].(NumberValue).Value))) + return MakeNumberValue(float64(int64(args[0].(NumberValue).Value) ^ int64(args[1].(NumberValue).Value))) } diff --git a/runtimelang/evalStatements.go b/runtimelang/evalStatements.go index a9499f9..67eec28 100644 --- a/runtimelang/evalStatements.go +++ b/runtimelang/evalStatements.go @@ -36,9 +36,9 @@ func EvaluateFunctionDeclaration(declaration ast.FunctionDeclaration, env Enviro func EvaluateVariableDeclaration(declaration ast.VariableDeclaration, env Environment) RuntimeValue { value, _ := Evaluate(declaration.Value, env) - if value.Type() == "object" { - value = value.(ObjectValue).Clone() - } + // if value.Type() == "object" { + // value = value.(ObjectValue).Clone() + // } return env.DeclareVariable(declaration.Identifier, value, declaration.Constant) } diff --git a/runtimelang/expressions.go b/runtimelang/expressions.go index 929e99a..e41f1c9 100644 --- a/runtimelang/expressions.go +++ b/runtimelang/expressions.go @@ -594,6 +594,30 @@ func EvaluateBinaryExpression(binaryExpression ast.BinaryExpression, env Environ return EvaluateNumericStringBinaryExpression(lhs.(NumberValue), rhs.(StringValue), binaryExpression.Operator) } else if lhs.Type() == "null" || rhs.Type() == "null" { return EvaluateNullBinaryExpression(lhs, rhs, binaryExpression.Operator) + } else if lhs.Type() == "object" && rhs.Type() == "object" { + return EvaluateObjectBinaryExpression(lhs.(ObjectValue), rhs.(ObjectValue), binaryExpression.Operator) + } + + + return MakeNullValue() +} + + +func EvaluateObjectBinaryExpression(lhs ObjectValue, rhs ObjectValue, op string) RuntimeValue { + if op == "==" { + for key, value := range lhs.Properties { + if !value.Equals(rhs.Properties[key]) { + return BoolValue{false} + } + } + return BoolValue{true} + } else if op == "!=" { + for key, value := range lhs.Properties { + if !value.Equals(rhs.Properties[key]) { + return BoolValue{true} + } + } + return BoolValue{false} } return MakeNullValue() @@ -605,14 +629,29 @@ func EvaluateNullBinaryExpression(lhs RuntimeValue, rhs RuntimeValue, op string) return BoolValue{true} } return BoolValue{false} - } else if lhs.Type() == "bool" && rhs.Type() != "null" { + } else if lhs.Type() == "bool" && rhs.Type() == "null" { + if op == "==" { + return BoolValue{false} + } + return BoolValue{true} + } else if lhs.Type() == "null" && rhs.Type() == "bool" { + if op == "==" { + return BoolValue{false} + } + return BoolValue{true} + } else if lhs.Type() == "object" && rhs.Type() == "null" { + if op == "==" { + return BoolValue{false} + } + return BoolValue{true} + } else if lhs.Type() == "null" && rhs.Type() == "object" { if op == "==" { return BoolValue{false} } return BoolValue{true} } - return MakeNullValue() + return MakeBoolValue(false) } func EvaluateStringNumericBinaryExpression(lhs StringValue, rhs NumberValue, op string) RuntimeValue { @@ -869,7 +908,6 @@ func EvaluateLogicalExpression(node ast.LogicalExpression, env Environment) Runt if err != nil { return nil } - fmt.Println(operand.Type()) if operand.Type() != Bool { fmt.Println("Error: not operator can only be applied to boolean values") os.Exit(0) diff --git a/runtimelang/values.go b/runtimelang/values.go index 9e806b4..8e0d96d 100644 --- a/runtimelang/values.go +++ b/runtimelang/values.go @@ -1,412 +1,525 @@ package runtimelang import ( - "strconv" + "strconv" - "github.com/Jamlee977/CustomLanguage/ast" + "github.com/Jamlee977/CustomLanguage/ast" ) type ValueType string const ( - Number ValueType = "number" - Null ValueType = "null" - String ValueType = "string" - Bool ValueType = "bool" - Object ValueType = "object" - Array ValueType = "array" - Tuple ValueType = "tuple" - NativeFunction ValueType = "native_function" - Function ValueType = "function" - Break ValueType = "break" - Class ValueType = "class" + Number ValueType = "number" + Null ValueType = "null" + String ValueType = "string" + Bool ValueType = "bool" + Object ValueType = "object" + Array ValueType = "array" + Tuple ValueType = "tuple" + NativeFunction ValueType = "native_function" + Function ValueType = "function" + Break ValueType = "break" + Class ValueType = "class" ) type RuntimeValue interface { - Get() any - Type() ValueType - ToString() string - Clone() RuntimeValue + Get() any + Type() ValueType + ToString() string + Clone() RuntimeValue + Equals(RuntimeValue) bool } type InitialValue struct{} +func (v InitialValue) Equals(other RuntimeValue) bool { + if other.Type() == Null { + return true + } + return false +} + func (v InitialValue) Type() ValueType { - return Null + return Null } func (v InitialValue) Get() any { - return "" + return "" } func (v InitialValue) ToString() string { - return "" + return "" } func (v InitialValue) Clone() RuntimeValue { - return v + return v } type NullValue struct { - Value string + Value string +} + +func (v NullValue) Equals(other RuntimeValue) bool { + if other.Type() == Null { + return true + } + return false } func (v NullValue) Type() ValueType { - return Object + return Null } func (v NullValue) Get() any { - return "null" + return "null" } func (v NullValue) ToString() string { - return "null" + return "null" } func (v NullValue) Clone() RuntimeValue { - return v + return v } func MakeNullValue() NullValue { - return NullValue{} + return NullValue{} } + type NumberValue struct { - Value float64 + Value float64 +} + +func (v NumberValue) Equals(other RuntimeValue) bool { + if other.Type() == Number { + return v.Value == other.Get().(float64) + } + return false } func (v NumberValue) Type() ValueType { - return Number + return Number } func (v NumberValue) Get() any { - return v.Value + return v.Value } func (v NumberValue) ToString() string { - return strconv.FormatFloat(v.Value, 'f', -1, 64) + return strconv.FormatFloat(v.Value, 'f', -1, 64) } func (v NumberValue) Clone() RuntimeValue { - return v + return v } func MakeNumberValue(value float64) NumberValue { - return NumberValue{Value: value} + return NumberValue{Value: value} } + type StringValue struct { - Value string + Value string +} + +func (v StringValue) Equals(other RuntimeValue) bool { + if other.Type() == String { + return v.Value == other.Get().(string) + } + return false } func (v StringValue) Type() ValueType { - return String + return String } func (v StringValue) Get() any { - return v.Value + return v.Value } func (v StringValue) ToString() string { - return v.Value + return v.Value } func (v StringValue) Clone() RuntimeValue { - return v + return v } func MakeStringValue(value string) StringValue { - return StringValue{Value: value} + return StringValue{Value: value} } + type BoolValue struct { - Value bool + Value bool +} + +func (v BoolValue) Equals(other RuntimeValue) bool { + if other.Type() == Bool { + return v.Value == other.Get().(bool) + } + return false } func (v BoolValue) Type() ValueType { - return Bool + return Bool } func (v BoolValue) Get() any { - return v.Value + return v.Value } func (v BoolValue) ToString() string { - return strconv.FormatBool(v.Value) + return strconv.FormatBool(v.Value) } func (v BoolValue) Clone() RuntimeValue { - return v + return v } func MakeBoolValue(value bool) BoolValue { - return BoolValue{Value: value} + return BoolValue{Value: value} } + type ObjectValue struct { - Properties map[string]RuntimeValue + Properties map[string]RuntimeValue +} + +func (v ObjectValue) Equals(other RuntimeValue) bool { + if other.Type() == Object { + otherObj := other.Get().(ObjectValue) + if len(v.Properties) != len(otherObj.Properties) { + return false + } + for key, value := range v.Properties { + if !value.Equals(otherObj.Properties[key]) { + return false + } + } + return true + } + return false } func (v ObjectValue) Type() ValueType { - return Object + return Object } func (v ObjectValue) Get() any { - str := "{ " - counter := 0 - for key, value := range v.Properties { - counter++ - str += key + ": " - - switch value.Type() { - case Null: - str += "null" - case Number: - str += value.ToString() - case String: - str += value.ToString() - case Bool: - str += value.ToString() - case Object: - str += value.ToString() - case Array: - str += value.ToString() - case Function: - str += value.Get().(string) - default: - str += "unknown" - } - - if counter < len(v.Properties) { - str += ", " - } - } - str += " }" - return str + str := "{ " + counter := 0 + for key, value := range v.Properties { + counter++ + str += key + ": " + + switch value.Type() { + case Null: + str += "null" + case Number: + str += value.ToString() + case String: + str += value.ToString() + case Bool: + str += value.ToString() + case Object: + str += value.ToString() + case Array: + str += value.ToString() + case Function: + str += value.Get().(string) + default: + str += "unknown" + } + + if counter < len(v.Properties) { + str += ", " + } + } + str += " }" + return str } func (v ObjectValue) ToString() string { - return v.Get().(string) + return v.Get().(string) } func (v ObjectValue) Clone() RuntimeValue { - newObject := ObjectValue{Properties: make(map[string]RuntimeValue)} - for key, value := range v.Properties { - newObject.Properties[key] = value.Clone() - } - return newObject + newObject := ObjectValue{Properties: make(map[string]RuntimeValue)} + for key, value := range v.Properties { + newObject.Properties[key] = value.Clone() + } + return newObject } + type ArrayValue struct { - Values []RuntimeValue + Values []RuntimeValue +} + +func (v ArrayValue) Equals(other RuntimeValue) bool { + if other.Type() == Array { + otherArray := other.(ArrayValue) + if len(v.Values) != len(otherArray.Values) { + return false + } + for i, value := range v.Values { + if !value.Equals(otherArray.Values[i]) { + return false + } + } + return true + } + return false } func (v ArrayValue) Type() ValueType { - return Array + return Array } func (v ArrayValue) Get() any { - str := "[ " - for i, value := range v.Values { - str += value.ToString() - if i < len(v.Values)-1 { - str += ", " - } - } - str += " ]" - return str + str := "[ " + for i, value := range v.Values { + str += value.ToString() + if i < len(v.Values)-1 { + str += ", " + } + } + str += " ]" + return str } func (v ArrayValue) ToString() string { - return v.Get().(string) + return v.Get().(string) } func (v ArrayValue) Clone() RuntimeValue { - newArray := ArrayValue{Values: make([]RuntimeValue, len(v.Values))} - copy(newArray.Values, v.Values) - return newArray + newArray := ArrayValue{Values: make([]RuntimeValue, len(v.Values))} + copy(newArray.Values, v.Values) + return newArray } + type TupleValue struct { - Values []RuntimeValue + Values []RuntimeValue +} + +func (v TupleValue) Equals(other RuntimeValue) bool { + if other.Type() == Tuple { + otherTuple := other.(TupleValue) + if len(v.Values) != len(otherTuple.Values) { + return false + } + for i, value := range v.Values { + if !value.Equals(otherTuple.Values[i]) { + return false + } + } + return true + } + return false } func (v TupleValue) Type() ValueType { - return Tuple + return Tuple } func (v TupleValue) Get() any { - str := "( " - for i, value := range v.Values { - str += value.ToString() - if i < len(v.Values)-1 { - str += ", " - } - } - str += " )" - return str + str := "( " + for i, value := range v.Values { + str += value.ToString() + if i < len(v.Values)-1 { + str += ", " + } + } + str += " )" + return str } func (v TupleValue) ToString() string { - return v.Get().(string) + return v.Get().(string) } func (v TupleValue) Clone() RuntimeValue { - newTuple := TupleValue{Values: make([]RuntimeValue, len(v.Values))} - copy(newTuple.Values, v.Values) - return newTuple + newTuple := TupleValue{Values: make([]RuntimeValue, len(v.Values))} + copy(newTuple.Values, v.Values) + return newTuple } + type FunctionCall func(args []RuntimeValue, env Environment) RuntimeValue type NativeFunctionValue struct { - Call FunctionCall + Call FunctionCall +} + +func (v NativeFunctionValue) Equals(other RuntimeValue) bool { + return false } func (v NativeFunctionValue) Type() ValueType { - return NativeFunction + return NativeFunction } func (v NativeFunctionValue) Get() any { - return v.Call + return v.Call } func (v NativeFunctionValue) ToString() string { - return "native function" + return "native function" } func (v NativeFunctionValue) Clone() RuntimeValue { - return v + return v } func MakeNativeFunction(call FunctionCall) NativeFunctionValue { - return NativeFunctionValue{Call: call} + return NativeFunctionValue{Call: call} } + type FunctionValue struct { - Name string - Parameters []string - DeclarationEnvironment Environment - Body []ast.Statement + Name string + Parameters []string + DeclarationEnvironment Environment + Body []ast.Statement +} + +func (v FunctionValue) Equals(other RuntimeValue) bool { + return false } func (v FunctionValue) Type() ValueType { - return Function + return Function } func (v FunctionValue) Get() any { - str := "fn " + v.Name + "(" - for i, param := range v.Parameters { - str += param - if i < len(v.Parameters)-1 { - str += ", " - } - } - str += ") { ... }" - return str + str := "fn " + v.Name + "(" + for i, param := range v.Parameters { + str += param + if i < len(v.Parameters)-1 { + str += ", " + } + } + str += ") { ... }" + return str } func (v FunctionValue) ToString() string { - return "function" + return "function" } func (v FunctionValue) Clone() RuntimeValue { - name := v.Name - parameters := make([]string, len(v.Parameters)) - copy(parameters, v.Parameters) - body := make([]ast.Statement, len(v.Body)) - copy(body, v.Body) - return &FunctionValue{ - Name: name, - Parameters: parameters, - DeclarationEnvironment: v.DeclarationEnvironment, - Body: body, - } + name := v.Name + parameters := make([]string, len(v.Parameters)) + copy(parameters, v.Parameters) + body := make([]ast.Statement, len(v.Body)) + copy(body, v.Body) + return &FunctionValue{ + Name: name, + Parameters: parameters, + DeclarationEnvironment: v.DeclarationEnvironment, + Body: body, + } } + type ReturnValue struct { - Value RuntimeValue + Value RuntimeValue +} + +func (v ReturnValue) Equals(other RuntimeValue) bool { + return false } type BreakType struct{} +func (v BreakType) Equals(other RuntimeValue) bool { + return false +} + func (v BreakType) Type() ValueType { - return Break + return Break } func (v BreakType) Get() any { - return nil + return nil } func (v BreakType) ToString() string { - return "break" + return "break" } func (v BreakType) Clone() RuntimeValue { - return v + return v } type ClassValue struct { - Name string - Constructor *FunctionValue - Methods map[string]*FunctionValue - Fields map[string]RuntimeValue + Name string + Constructor *FunctionValue + Methods map[string]*FunctionValue + Fields map[string]RuntimeValue +} + +func (v ClassValue) Equals(other RuntimeValue) bool { + return false } func (v ClassValue) Type() ValueType { - return Class + return Class } func (v ClassValue) Get() any { - return v.Methods + return v.Methods } func (v ClassValue) ToString() string { - return "class" + return "class" } func (v ClassValue) Clone() RuntimeValue { - methods := make(map[string]*FunctionValue) - for k, v := range v.Methods { - methods[k] = v.Clone().(*FunctionValue) - } - fields := make(map[string]RuntimeValue) - for k, v := range v.Fields { - fields[k] = v.Clone() - } + methods := make(map[string]*FunctionValue) + for k, v := range v.Methods { + methods[k] = v.Clone().(*FunctionValue) + } + fields := make(map[string]RuntimeValue) + for k, v := range v.Fields { + fields[k] = v.Clone() + } - constructor := v.Constructor.Clone().(*FunctionValue) - return ClassValue{Name: v.Name, Constructor: constructor, Methods: methods, Fields: fields} + constructor := v.Constructor.Clone().(*FunctionValue) + return ClassValue{Name: v.Name, Constructor: constructor, Methods: methods, Fields: fields} } func MakeClassValue(name string, methods map[string]*FunctionValue) ClassValue { - return ClassValue{Name: name, Methods: methods} + return ClassValue{Name: name, Methods: methods} } func MakeArrayValue(values []RuntimeValue) ArrayValue { - return ArrayValue{Values: values} + return ArrayValue{Values: values} } func MakeTupleValue(values []RuntimeValue) TupleValue { - return TupleValue{Values: values} + return TupleValue{Values: values} } func MakeObjectValue(properties map[string]RuntimeValue) ObjectValue { - return ObjectValue{Properties: properties} + return ObjectValue{Properties: properties} } func ToGoArrayValue(v ArrayValue) []RuntimeValue { - return v.Values + return v.Values } func ToGoNumberValue(v NumberValue) float64 { - return v.Value + return v.Value } func ToGoStringValue(v StringValue) string { - return v.Value + return v.Value } func ToGoTupleValue(v TupleValue) []RuntimeValue { - return v.Values + return v.Values } diff --git a/std/linkedlist.jam b/std/linkedlist.jam index ba3f9c2..2a8140f 100644 --- a/std/linkedlist.jam +++ b/std/linkedlist.jam @@ -1,79 +1,60 @@ fn Node(value) { return { - value, - next: null, + value: value, + next: null } } fn LinkedList() { - let head = null + let head = null; fn add(value) { - const node = Node(value) - - if not head { - head = node + let node = Node(value); + if head == null { + head = node; } else { - let current = head + let current = head; while current.next != null { - current = current.next + current = current.next; } - current.next = node - } - } - - fn display() { - let current = head - let result = "" - while current != null { - result = result + current.value + " -> " - current = current.next - } - println(result + "null") - } - - fn length() { - let count = 0 - let current = head - while current != null { - ++count - current = current.next + current.next = node; } - return count } - fn search(value) { - let current = head + fn printList() { + let current = head; + print("[ ") while current != null { - if current.value == value { - return current + if current.next == null { + print(current.value) + break } - current = current.next + print(current.value, ", "); + current = current.next; } - return null + println(" ]") } fn remove(value) { - if not head { - return null - } - - if head.value == value { - head = head.next - } else { - let current = head - while current.next != null { - if current.next.value == value { - current.next = current.next.next - break + let current = head; + let previous = null; + while current != null { + if current.value == value { + if previous == null { + head = current.next; + } else { + previous.next = current.next; } - current = current.next + break; } + previous = current; + current = current.next; } } return { add, - display, + printList, + remove, } } diff --git a/std/random.jam b/std/random.jam deleted file mode 100644 index c6dc519..0000000 --- a/std/random.jam +++ /dev/null @@ -1,124 +0,0 @@ -const __N = 624 -const __M = 397 -const __A = hex("9908b0df") -const __U = 11 -const __D = hex("ffffffff") -const __S = 7 -const __B = hex("9d2c5680") -const __T = 15 -const __C = hex("efc60000") -const __L = 18 -const __F = 1812433253 -const __LOWER_MASK = hex("7fffffff") -const __UPPER_MASK = Bitwise.NOT(__LOWER_MASK) -const __MAX_INT = hex("ffffffff") -const __DOUBLE_UNIT = 1 << 53 - -let __state = [] -let __index = 0 - -fn __twist() { - let i = 0 - while i < __N { - let x = (__state[i] & __UPPER_MASK) + (__state[(i + 1) % __N] & __LOWER_MASK) - let xA = x >> 1 - if (x & 1) != 0 { - xA = xA ^ x - } - __state[i] = __state[(i + __M) % __N] ^ xA - ++i - } - __index = 0 -} - -fn __next(bits) { - if __index >= __N { - __twist() - } - let y = __state[__index] - ++__index - y = y ^ (y >> __U) - y = y ^ ((y << __S) & __B) - y = y ^ ((y << __T) & __C) - y = y ^ (y >> __L) - return y >> (32 - bits) -} - -fn __new() { - __index = __N - __state = append(__state, Time.now()) - let i = 1 - while i < __N { - __state = append(__state, (__F * (__state[i - 1] ^ (__state[i - 1] >> 30)) + i)) - ++i - } -} - -fn __nextInt() { - return __next(32) -} - -fn __nextIntBounded(bound) { - let r = __next(31) - let m = bound - 1 - if (bound & m) == 0 { - r = ((bound * (r // 1)) >> 31) // 1 - } else { - let u = r - while u - (r = u % bound) + m < 0 { - u = __next(31) - } - } - return r -} - -fn __nextLong() { - return (__next(32) << 32) + __next(32) -} - -fn __nextLongBounded(bound) { - let r = __nextLong() & hex("7fffffffffffffff") - let m = bound - 1 - if (bound & m) == 0 { - r = ((bound * (r // 1)) >> 63) // 1 - } else { - let u = r - while u - (r = u % bound) + m < 0 { - u = __nextLong() & hex("7fffffffffffffff") - } - } - - return r -} - -fn __nextBool() { - return __next(1) != 0 -} - -fn __nextFloat() { - return __next(24) / (1 << 24) -} - -fn __nextFloatRanged(from, to) { - return from + __nextFloat() * (to - from) -} - -fn __nextDouble() { - return (((__next(26) // 1) << 27) + __next(27)) / __DOUBLE_UNIT -} - -fn __nextDoubleRanged(from, to) { - return from + __nextDouble() * (to - from) -} - -const Random = { - new: __new, - nextInt: __nextInt, - nextIntBounded: __nextIntBounded, - nextLong: __nextLong, - nextLongBounded: __nextLongBounded, - nextFloat: __nextFloat, - nextFloatRanged: __nextFloatRanged, - nextDouble: __nextDouble, - nextDoubleRanged: __nextDoubleRanged, -} diff --git a/test.jam b/test.jam index aef0beb..74b7cbf 100644 --- a/test.jam +++ b/test.jam @@ -1,10 +1,27 @@ +import "std/algorithm.jam" +import "std/linkedlist.jam" + +let x = sort([1,2,4,5,2,5,5]) +println(x) + +const list = LinkedList() +list.add(1) +list.add(2) +list.add(3) +list.add(4) +list.add(5) +list.add(6) +list.add(7) +list.printList() +list.remove(2) +list.printList() + fn adder(x) { - fn sum(y) { + fn add(y) { return x + y } - return sum + return add } -const addTwo = adder(2) - -println(addTwo(3)) +let add5 = adder(5) +println(add5(2))