Skip to content

Commit 801a74a

Browse files
committed
wip
Signed-off-by: James Hamlin <jfhamlin@gmail.com>
1 parent 715ad47 commit 801a74a

2 files changed

Lines changed: 99 additions & 28 deletions

File tree

pkg/codegen/codegen.go

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,9 @@ func (g *Generator) Generate(ns *lang.Namespace) error {
8181
g.writef(" ns := lang.FindOrCreateNamespace(lang.NewSymbol(\"%s\"))\n", ns.Name().String())
8282
g.writef(" _ = ns\n")
8383

84-
// TODO: Generate code to populate the namespace
85-
// This will involve:
86-
// 1. Iterating through ns.Mappings()
87-
// 2. Generating Go code for each var
88-
// 3. Creating initialization functions
84+
// 1. Iterate through ns.Mappings()
85+
// 2. Generate Go code for each var
86+
// 3. Create initialization functions
8987
for seq := mappings.Seq(); seq != nil; seq = seq.Next() {
9088
entry := seq.First()
9189
name, ok := lang.First(entry).(*lang.Symbol)
@@ -346,7 +344,6 @@ func (g *Generator) generateFnMethod(methodNode *ast.FnMethodNode, argsVar strin
346344

347345
// generateASTNode generates code for an AST node
348346
func (g *Generator) generateASTNode(node *ast.Node) string {
349-
fmt.Printf("Generating code for AST node: %T %+v\n", node.Sub, node.Sub)
350347
switch node.Op {
351348
case ast.OpConst:
352349
constNode := node.Sub.(*ast.ConstNode)
@@ -363,42 +360,72 @@ func (g *Generator) generateASTNode(node *ast.Node) string {
363360
return g.generateIf(node)
364361
case ast.OpInvoke:
365362
return g.generateInvoke(node)
363+
case ast.OpVar:
364+
return g.generateVarDeref(node)
365+
case ast.OpRecur:
366+
return g.generateRecur(node)
366367
default:
368+
fmt.Printf("Generating code for AST node: %T %+v\n", node.Sub, node.Sub)
367369
panic(fmt.Sprintf("unsupported AST node type %T", node.Sub))
368370
}
369371
}
370372

373+
// generateVarDeref generates code for a Var dereference
374+
func (g *Generator) generateVarDeref(node *ast.Node) string {
375+
varNode := node.Sub.(*ast.VarNode)
376+
377+
varNamespace := varNode.Var.Namespace()
378+
varSymbol := varNode.Var.Symbol()
379+
380+
// generate code to look up the var in the namespace
381+
nsVar := g.allocateVar("ns")
382+
g.writef("%s := lang.FindNamespace(lang.NewSymbol(\"%s\"))\n", nsVar, varNamespace.Name())
383+
// look up the var in the namespace
384+
varId := g.allocateVar("varId")
385+
g.writef("%s := %s.FindInternedVar(lang.NewSymbol(\"%s\"))\n", varId, nsVar, varSymbol.Name())
386+
387+
// if macro, panic with 'can't take value of macro: %v'
388+
g.writef("if %s.IsMacro() {\n", varId)
389+
g.writef(" panic(lang.NewIllegalArgumentError(\"can't take value of macro: %v\"))\n", varId)
390+
g.writef("}\n")
391+
// else, return Get()
392+
resultId := g.allocateVar("result")
393+
g.writef("%s := %s.Get()\n", resultId, varId)
394+
395+
return resultId
396+
}
397+
371398
// generateInvoke generates code for an Invoke node
372399
func (g *Generator) generateInvoke(node *ast.Node) string {
373400
invokeNode := node.Sub.(*ast.InvokeNode)
374-
401+
375402
// Generate the function expression
376403
fnExpr := g.generateASTNode(invokeNode.Fn)
377-
404+
378405
// Generate the arguments
379406
var argExprs []string
380407
for _, arg := range invokeNode.Args {
381408
argExprs = append(argExprs, g.generateASTNode(arg))
382409
}
383-
410+
384411
// Allocate a result variable for the invocation
385412
resultVar := g.allocateVar("invokeResult")
386-
413+
387414
// Emit the invocation
388415
if len(argExprs) == 0 {
389-
g.writef("%s := lang.Invoke(%s)\n", resultVar, fnExpr)
416+
g.writef("%s := lang.Apply(%s, nil)\n", resultVar, fnExpr)
390417
} else {
391-
g.writef("%s := lang.Invoke(%s, %s)\n", resultVar, fnExpr, strings.Join(argExprs, ", "))
418+
g.writef("%s := lang.Apply(%s, []any{%s})\n", resultVar, fnExpr, strings.Join(argExprs, ", "))
392419
}
393-
420+
394421
// Return the result variable
395422
return resultVar
396423
}
397424

398425
// generateDo generates code for a Do node
399426
func (g *Generator) generateDo(node *ast.Node) string {
400427
doNode := node.Sub.(*ast.DoNode)
401-
428+
402429
// Emit all statements except the last to g.w
403430
for _, stmt := range doNode.Statements {
404431
if stmt == nil {
@@ -407,7 +434,7 @@ func (g *Generator) generateDo(node *ast.Node) string {
407434
stmtResult := g.generateASTNode(stmt)
408435
g.writef("_ = %s\n", stmtResult) // Discard intermediate results
409436
}
410-
437+
411438
// Return the final expression
412439
return g.generateASTNode(doNode.Ret)
413440
}
@@ -418,7 +445,7 @@ func (g *Generator) generateIf(node *ast.Node) string {
418445

419446
// Allocate result variable
420447
resultVar := g.allocateVar("ifResult")
421-
448+
422449
// Emit the if statement to g.w
423450
g.writef("var %s any\n", resultVar)
424451
testExpr := g.generateASTNode(ifNode.Test)
@@ -433,7 +460,7 @@ func (g *Generator) generateIf(node *ast.Node) string {
433460
g.writef(" %s = nil\n", resultVar)
434461
}
435462
g.writef("}\n")
436-
463+
437464
// Return the r-value
438465
return resultVar
439466
}
@@ -510,8 +537,35 @@ func (g *Generator) generateLet(node *ast.Node, isLoop bool) string {
510537
g.writef("%s := %s\n", varName, initCode)
511538
}
512539

540+
resultId := g.allocateVar("letResult")
541+
if isLoop {
542+
g.writef("var %s any\n", resultId)
543+
g.writef("for {\n")
544+
}
545+
513546
// Return the body expression (r-value)
514-
return g.generateASTNode(letNode.Body)
547+
result := g.generateASTNode(letNode.Body)
548+
if isLoop {
549+
g.writef(" %s = %s\n", resultId, result)
550+
g.writef(" break\n") // Break out of the loop after the body
551+
g.writef("}\n")
552+
return resultId
553+
} else {
554+
return result
555+
}
556+
}
557+
558+
func (g *Generator) generateRecur(node *ast.Node) string {
559+
recurNode := node.Sub.(*ast.RecurNode)
560+
561+
exprs := recurNode.Exprs
562+
for _, expr := range exprs {
563+
val, err := noRecurEnv.EvalAST(expr)
564+
if err != nil {
565+
return nil, err
566+
}
567+
vals = append(vals, val)
568+
}
515569
}
516570

517571
////////////////////////////////////////////////////////////////////////////////

pkg/codegen/testdata/codegen/test/loop_simple.go

Lines changed: 27 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)