Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions backend/cmd/compute/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/genshinsim/gcsim/backend/pkg/services/db"
"github.com/genshinsim/gcsim/pkg/gcs/ast"
"github.com/genshinsim/gcsim/pkg/model"
"github.com/genshinsim/gcsim/pkg/simulator"
"google.golang.org/grpc"
Expand Down Expand Up @@ -118,7 +119,8 @@ func (c *client) processWork(w *db.ComputeWork) (*model.SimulationResult, error)
// compute work??
log.Printf("got work %v; starting compute", w.Id)
// compute result
simcfg, gcsl, err := simulator.Parse(w.Config)
file := ast.NewFile()
simcfg, gcsl, err := simulator.Parse(file, w.Config)
if err != nil {
log.Printf("could not parse config for id %v: %v\n", w.Id, err)
// TODO: we should post something here??
Expand All @@ -130,7 +132,7 @@ func (c *client) processWork(w *db.ComputeWork) (*model.SimulationResult, error)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(c.timeoutInSec)*time.Second)
defer cancel()

result, err := simulator.RunWithConfig(ctx, w.Config, simcfg, gcsl, simulator.Options{}, time.Now())
result, err := simulator.RunWithConfig(ctx, file, w.Config, simcfg, gcsl, simulator.Options{}, time.Now())
if err != nil {
log.Printf("error running sim %v: %v\n", w.Id, err)
return nil, err
Expand Down
26 changes: 26 additions & 0 deletions pkg/gcs/ast/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ast

import "fmt"

type Error struct {
Pos Position
Msg string
}

func (e Error) Error() string {
if !e.Pos.IsValid() {
return e.Msg
}
return fmt.Sprintf("ln%v: %v", e.Pos, e.Msg)
}

func NewError(pos Position, msg string) Error {
return Error{
Pos: pos,
Msg: msg,
}
}

func NewErrorf(pos Position, format string, a ...any) Error {
return NewError(pos, fmt.Sprintf(format, a...))
}
8 changes: 6 additions & 2 deletions pkg/gcs/ast/lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type stateFn func(*Lexer) stateFn

// Lexer holds the state of the scanner.
type Lexer struct {
file *File
input string // the string being scanned
pos Pos // current position in the input
start Pos // start position of this item
Expand All @@ -38,6 +39,7 @@ func (l *Lexer) next() rune {
l.pos += l.width
if r == '\n' {
l.line++
l.file.AddLine(int(l.pos))
}
return r
}
Expand Down Expand Up @@ -112,8 +114,10 @@ func (l *Lexer) NextItem() Token {
}

// lex creates a new scanner for the input string.
func NewLexer(input string) *Lexer {
func NewLexer(file *File, input string) *Lexer {
file.size = len(input)
l := &Lexer{
file: file,
input: input,
items: make(chan Token),
line: 1,
Expand Down Expand Up @@ -424,7 +428,7 @@ func (l *Lexer) atTerminator() bool {
return true
}
switch r {
case eof, '.', ',', '|', ':', ')', '(', '+', '=', '>', '<', '&', '!', ';', '[', ']', '{', '}':
case eof, '.', ',', '|', ':', ')', '(', '+', '=', '>', '<', '&', '!', ';', '[', ']', '{', '}', '/', '*':
return true
}
return false
Expand Down
9 changes: 6 additions & 3 deletions pkg/gcs/ast/lex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
func TestFields(t *testing.T) {
input := `if .status.field > 0 { print("hi") };`

l := NewLexer(input)
file := NewFile()
l := NewLexer(file, input)
for n := l.NextItem(); n.Typ != ItemEOF; n = l.NextItem() {
fmt.Println(n)
}
Expand Down Expand Up @@ -166,7 +167,8 @@ func TestBasicToken(t *testing.T) {
{Typ: ItemIdentifier, Val: "a"},
}

l := NewLexer(input)
file := NewFile()
l := NewLexer(file, input)
i := 0
for n := l.NextItem(); n.Typ != ItemEOF; n = l.NextItem() {
if expected[i].Typ != n.Typ && expected[i].Val != n.Val {
Expand Down Expand Up @@ -196,7 +198,8 @@ func TestElseSpace(t *testing.T) {
{Typ: ItemRightBrace, Val: "}"},
}

l := NewLexer(input)
file := NewFile()
l := NewLexer(file, input)
i := 0
for n := l.NextItem(); n.Typ != ItemEOF; n = l.NextItem() {
if expected[i].Typ != n.Typ && expected[i].Val != n.Val {
Expand Down
47 changes: 47 additions & 0 deletions pkg/gcs/ast/position.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package ast

import (
"fmt"
"sort"
)

type Position struct {
Line int
Column int
}

func (p Position) IsValid() bool { return p.Line > 0 }

func (p Position) String() string {
if !p.IsValid() {
return "-"
}
return fmt.Sprintf("%v:%v", p.Line, p.Column)
}

type File struct {
size int
lines []int
}

func (f *File) AddLine(offset int) {
if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset < f.size {
f.lines = append(f.lines, offset)
}
}

func (f *File) Position(offset Pos) Position {
line := sort.Search(len(f.lines), func(i int) bool { return f.lines[i] > int(offset) }) - 1
if line < 0 {
return Position{}
}

return Position{
Line: line + 1,
Column: int(offset) - f.lines[line] + 1,
}
}

func NewFile() *File {
return &File{lines: []int{0}}
}
4 changes: 3 additions & 1 deletion pkg/gcs/eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Eval struct {
Core *core.Core
AST ast.Node
Log *log.Logger
file *ast.File

next chan bool // wait on this before continuing
work chan *action.Eval // send work to this chan
Expand All @@ -31,10 +32,11 @@ type Env struct {
varMap map[string]*Obj
}

func NewEvaluator(ast ast.Node, c *core.Core) (*Eval, error) {
func NewEvaluator(file *ast.File, ast ast.Node, c *core.Core) (*Eval, error) {
e := &Eval{
AST: ast,
Core: c,
file: file,
next: make(chan bool),
work: make(chan *action.Eval),
}
Expand Down
31 changes: 19 additions & 12 deletions pkg/gcs/eval/eval_fn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"log"
"testing"

"github.com/genshinsim/gcsim/pkg/gcs/ast"
"github.com/genshinsim/gcsim/pkg/gcs/parser"
)

Expand All @@ -20,14 +21,15 @@ func TestFib(t *testing.T) {
print(y);
return y;
`
p := parser.New(prog)
file := ast.NewFile()
p := parser.New(file, prog)
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
fmt.Println("program:")
fmt.Println(gcsl.String())
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
resultChan := make(chan Obj)
go func() {
Expand Down Expand Up @@ -75,14 +77,15 @@ func TestFunctional(t *testing.T) {
print(x);
return x;
`
p := parser.New(prog)
file := ast.NewFile()
p := parser.New(file, prog)
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
fmt.Println("program:")
fmt.Println(gcsl.String())
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
resultChan := make(chan Obj)
go func() {
Expand Down Expand Up @@ -125,12 +128,13 @@ func TestAnonFunc(t *testing.T) {
print(x);
return x;
`
p := parser.New(prog)
file := ast.NewFile()
p := parser.New(file, prog)
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
resultChan := make(chan Obj)
go func() {
Expand Down Expand Up @@ -173,12 +177,13 @@ func TestStringFunc(t *testing.T) {
print(x);
return x;
`
p := parser.New(prog)
file := ast.NewFile()
p := parser.New(file, prog)
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
resultChan := make(chan Obj)
go func() {
Expand Down Expand Up @@ -222,14 +227,15 @@ func TestNestedActions(t *testing.T) {
}
do();
`
p := parser.New(prog)
file := ast.NewFile()
p := parser.New(file, prog)
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
fmt.Println("program:")
fmt.Println(gcsl.String())
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
resultChan := make(chan Obj)
go func() {
Expand Down Expand Up @@ -262,14 +268,15 @@ func TestNestedActions(t *testing.T) {

func TestIsEven(t *testing.T) {
prog := `is_even(1);`
p := parser.New(prog)
file := ast.NewFile()
p := parser.New(file, prog)
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
fmt.Println("program:")
fmt.Println(gcsl.String())
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
resultChan := make(chan Obj)
go func() {
Expand Down
21 changes: 13 additions & 8 deletions pkg/gcs/eval/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ import (
"testing"

"github.com/genshinsim/gcsim/pkg/core/action"
"github.com/genshinsim/gcsim/pkg/gcs/ast"
"github.com/genshinsim/gcsim/pkg/gcs/parser"
)

func TestType(t *testing.T) {
p := parser.New("type(1);")
file := ast.NewFile()
p := parser.New(file, "type(1);")
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
resultChan := make(chan Obj)
go func() {
Expand Down Expand Up @@ -44,15 +46,16 @@ func TestType(t *testing.T) {

func TestForceTerminate(t *testing.T) {
// test terminate eval early should gracefully exit
p := parser.New(`
file := ast.NewFile()
p := parser.New(file, `
for let i = 0; i < 50; i = i + 1 {
delay(1);
}`)
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
go func() {
res, err := eval.Run()
Expand Down Expand Up @@ -94,12 +97,13 @@ func TestForceTerminate(t *testing.T) {

func TestSleepAsWaitAlias(t *testing.T) {
// make sure sleep is evaluated as wait
p := parser.New("sleep(1);")
file := ast.NewFile()
p := parser.New(file, "sleep(1);")
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
go func() {
res, err := eval.Run()
Expand Down Expand Up @@ -129,15 +133,16 @@ func TestSleepAsWaitAlias(t *testing.T) {

func TestDoneCheck(t *testing.T) {
// eval should exit once out of action; NextAction() should return nil
p := parser.New(`
file := ast.NewFile()
p := parser.New(file, `
for let i = 0; i < 4; i = i + 1 {
delay(1);
}`)
_, gcsl, err := p.Parse()
if err != nil {
t.Fatal(err)
}
eval, _ := NewEvaluator(gcsl, nil)
eval, _ := NewEvaluator(file, gcsl, nil)
eval.Log = log.Default()
go func() {
res, err := eval.Run()
Expand Down
Loading