Skip to content

Commit

Permalink
Added anonymous functions using fn() syntax, classes are broken so a …
Browse files Browse the repository at this point in the history
…function with inner anonymous functions could work instead. Converted functions from statements into expressions
  • Loading branch information
Jamlie committed Oct 9, 2023
1 parent 851edfa commit 30f3c63
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 47 deletions.
8 changes: 7 additions & 1 deletion ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,20 @@ type FunctionDeclaration struct {
Parameters []string
Name string
Body []Statement
IsAnonymous bool
}

func (f *FunctionDeclaration) Kind() NodeType {
return FunctionDeclarationType
}

func (f *FunctionDeclaration) ToString() string {
s := "function " + f.Name + "("
var s string
if f.IsAnonymous {
s = "function("
} else {
s = "function " + f.Name + "("
}
for i, param := range f.Parameters {
if i > 0 {
s += ", "
Expand Down
Binary file modified bin/jamlang.exe
Binary file not shown.
Binary file added bin/jamlang.out
Binary file not shown.
10 changes: 8 additions & 2 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,11 @@ func (p *Parser) parseClassDeclaration() ast.Statement {

func (p *Parser) parseFunctionDeclaration() ast.Statement {
p.eat()
name := p.expect(tokentype.Identifier, "Error: Expected function name after fn keyword").Value
var name string

if p.at().Type != tokentype.OpenParen {
name = p.expect(tokentype.Identifier, "Error: Expected function name after fn keyword").Value
}

args := p.parseArgs()
var params []string
Expand Down Expand Up @@ -659,11 +663,13 @@ func (p *Parser) parsePrimaryExpression() ast.Expression {
Operator: operator,
Value: value,
}
case tokentype.Function:
return p.parseFunctionDeclaration()
default:
fmt.Println("Unexpected token found: ", p.at())
os.Exit(0)
return nil
}
}
}

func (p *Parser) at() lexer.Token {
Expand Down
20 changes: 5 additions & 15 deletions runtimelang/evalStatements.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,15 @@ func EvaluateReturnStatement(statement ast.ReturnStatement, env Environment) Run
return returnValue
}

func EvaluateFunctionDeclaration(declaration ast.FunctionDeclaration, env Environment) RuntimeValue {
fn := FunctionValue{
Name: declaration.Name,
Parameters: declaration.Parameters,
DeclarationEnvironment: env,
Body: declaration.Body,
func EvaluateVariableDeclaration(declaration ast.VariableDeclaration, env *Environment) RuntimeValue {
value, _ := Evaluate(declaration.Value, *env)
if value.Type() == "object" && value.(ObjectValue).IsClass {
value = value.(ObjectValue).Clone()
}
return env.DeclareVariable(declaration.Name, &fn, true)
}

func EvaluateVariableDeclaration(declaration ast.VariableDeclaration, env Environment) RuntimeValue {
value, _ := Evaluate(declaration.Value, env)
// if value.Type() == "object" {
// value = value.(ObjectValue).Clone()
// }
return env.DeclareVariable(declaration.Identifier, value, declaration.Constant)
}

func EvaluateIdentifier(identifier *ast.Identifier, env Environment) RuntimeValue {
func EvaluateIdentifier(identifier *ast.Identifier, env *Environment) RuntimeValue {
if identifier == nil {
return MakeNullValue()
}
Expand Down
33 changes: 31 additions & 2 deletions runtimelang/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,37 @@ var (
IsBreakError = fmt.Errorf("break statement error")
)

func EvaluateFunctionDeclaration(expr ast.FunctionDeclaration, env *Environment) (RuntimeValue, error) {
var fn FunctionValue
if expr.Name == "" {
expr.IsAnonymous = true
}
if expr.IsAnonymous {
fn = FunctionValue{
Body: expr.CloneBody(),
Parameters: expr.CloneParameters(),
DeclarationEnvironment: *env,
IsAnonymous: true,
}
} else {
fn = FunctionValue{
Name: expr.Name,
Body: expr.CloneBody(),
Parameters: expr.CloneParameters(),
DeclarationEnvironment: *env,
}

env.DeclareVariable(expr.Name, fn, true)
}

return fn, nil
}

func EvaluateClassDeclaration(expr ast.ClassDeclaration, env *Environment) (RuntimeValue, error) {
class := ObjectValue{map[string]RuntimeValue{}}
class := ObjectValue{
Properties: map[string]RuntimeValue{},
IsClass: true,
}
actualClass := ClassValue{
Name: expr.Name,
Methods: make(map[string]*FunctionValue),
Expand Down Expand Up @@ -411,7 +440,7 @@ func EvaluateCallExpression(expr ast.CallExpression, env Environment) RuntimeVal
result := function.(NativeFunctionValue).Call(args, env)
return result
} else if function.Type() == Function {
fn := function.(*FunctionValue)
fn := function.(FunctionValue)
scope := NewEnvironment(&fn.DeclarationEnvironment)

for i := 0; i < len(fn.Parameters); i++ {
Expand Down
8 changes: 5 additions & 3 deletions runtimelang/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func Evaluate(astNode ast.Statement, env Environment) (RuntimeValue, error) {
os.Exit(0)
return nil, nil
}
return EvaluateIdentifier(identifier, env), nil
return EvaluateIdentifier(identifier, &env), nil
case ast.ObjectLiteralType:
objectLiteral, ok := astNode.(*ast.ObjectLiteral)
if !ok {
Expand Down Expand Up @@ -134,15 +134,17 @@ func Evaluate(astNode ast.Statement, env Environment) (RuntimeValue, error) {
os.Exit(0)
return nil, nil
}
return EvaluateVariableDeclaration(*variableDeclaration, env), nil
return EvaluateVariableDeclaration(*variableDeclaration, &env), nil
case ast.FunctionDeclarationType:
functionDeclaration, ok := astNode.(*ast.FunctionDeclaration)
if !ok {
fmt.Printf("Error: Expected FunctionDeclaration, got %T\n", astNode)
os.Exit(0)
return nil, nil
}
return EvaluateFunctionDeclaration(*functionDeclaration, env), nil

fn, _ := EvaluateFunctionDeclaration(*functionDeclaration, &env)
return fn, nil
case ast.ConditionalStatementType:
conditionalStatement, ok := astNode.(*ast.ConditionalStatement)
if !ok {
Expand Down
2 changes: 2 additions & 0 deletions runtimelang/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ func MakeBoolValue(value bool) BoolValue {

type ObjectValue struct {
Properties map[string]RuntimeValue
IsClass bool
}

func (v ObjectValue) Equals(other RuntimeValue) bool {
Expand Down Expand Up @@ -384,6 +385,7 @@ type FunctionValue struct {
Parameters []string
DeclarationEnvironment Environment
Body []ast.Statement
IsAnonymous bool
}

func (v FunctionValue) Equals(other RuntimeValue) bool {
Expand Down
79 changes: 55 additions & 24 deletions test.jam
Original file line number Diff line number Diff line change
@@ -1,27 +1,58 @@
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 add(y) {
return x + y
fn Person(name, age) {
let this = {}
this.name = name
this.age = age

this.sayHello = fn() {
println("hello")
}

this.getName = fn() {
return this.name
}

this.getAge = fn() {
return this.age
}

this.setName = fn(name) {
this.name = name
}

this.setAge = fn(age) {
this.age = age
}

return this
}

const foo = Person("foo", 20)
const bar = Person("bar", 25)

foo.setName("baz")

println(foo.getName())
println(bar.getName())

const StringBuilder = {
new: fn() {
let this = {}
this.str = ""

this.append = fn(s) {
this.str = this.str + s
}

this.toString = fn() {
return this.str
}

return this
}
return add
}

let add5 = adder(5)
println(add5(2))
const sb = StringBuilder.new()
sb.append("hello")
sb.append(" world")

println(sb.toString())

0 comments on commit 30f3c63

Please sign in to comment.