diff --git a/lang/code/ast/common/func_call.go b/lang/code/ast/common/func_call.go index 6cccf249..832edbe1 100644 --- a/lang/code/ast/common/func_call.go +++ b/lang/code/ast/common/func_call.go @@ -80,6 +80,8 @@ var signatures = map[string]*FuncCallSignature{ "makeColor": makeSignature("makeColor", 1, ast.SignNumb), "splitColor": makeSignature("splitColor", 1, ast.SignList), + "makeNdArray": makeSignature("makeNdArray", 2, ast.SignList), + "set": makeSignature("set", 4, ast.SignVoid), "get": makeSignature("get", 3, ast.SignAny), "call": makeSignature("call", -1-(3), ast.SignVoid), @@ -180,17 +182,20 @@ func (f *FuncCall) Blockly(flags ...bool) ast.Block { case "getPlainStartText": return f.ctrlSimpleBlock("controls_getPlainStartText") case "closeScreenWithPlainText": + return f.closeScreenWithPlainText() case "copyList": return f.copyList() case "copyDict": return f.copyDict() - case "makeColor": return f.makeColor() case "splitColor": return f.splitColor() + case "makeNdArray": + return f.makeNdArray() + case "set": return f.genericSet() case "get": @@ -318,6 +323,13 @@ func (f *FuncCall) genericSet() ast.Block { } } +func (f *FuncCall) makeNdArray() ast.Block { + return ast.Block{ + Type: "matrices_create_multidim", + Values: ast.MakeValues(f.Args, "DIM", "INITIAL"), + } +} + func (f *FuncCall) splitColor() ast.Block { return ast.Block{ Type: "color_make_color", diff --git a/lang/code/ast/common/question.go b/lang/code/ast/common/question.go index 67f704d0..1161732b 100644 --- a/lang/code/ast/common/question.go +++ b/lang/code/ast/common/question.go @@ -31,6 +31,8 @@ func (q *Question) Blockly(flags ...bool) ast.Block { return q.listQuestion() case "dict": return q.dictQuestion() + case "matrix": + return q.matrixQuestion() case "emptyText": return q.textIsEmpty() case "emptyList": @@ -89,6 +91,13 @@ func (q *Question) textIsEmpty() ast.Block { } } +func (q *Question) matrixQuestion() ast.Block { + return ast.Block{ + Type: "matrices_is_matrix", + Values: []ast.Value{{Name: "VALUE", Block: q.On.Blockly(false)}}, + } +} + func (q *Question) dictQuestion() ast.Block { return ast.Block{ Type: "dictionaries_is_dict", diff --git a/lang/code/ast/method/call.go b/lang/code/ast/method/call.go index 1a5f7c91..66ca69dc 100644 --- a/lang/code/ast/method/call.go +++ b/lang/code/ast/method/call.go @@ -91,6 +91,14 @@ var signatures = map[string]*CallSignature{ "keys": makeSignature("dict", "dictionaries_getters", 0, true, ast.SignList), "values": makeSignature("dict", "dictionaries_getters", 0, true, ast.SignList), "toPairs": makeSignature("dict", "dictionaries_dict_to_alist", 0, true, ast.SignList), + + "row": makeSignature("matrix", "matrices_get_row", 1, true, ast.SignAny), + "col": makeSignature("matrix", "matrices_get_column", 1, true, ast.SignAny), + "dimension": makeSignature("matrix", "matrices_get_dims", 1, true, ast.SignList), + "inverse": makeSignature("matrix", "matrices_operations", 0, true, ast.SignList), + "transpose": makeSignature("matrix", "matrices_operations", 0, true, ast.SignList), + "rotateLeft": makeSignature("matrix", "matrices_operations", 0, true, ast.SignList), + "rotateRight": makeSignature("matrix", "matrices_operations", 0, true, ast.SignList), } func TestSignature(methodName string, argsCount int) (string, *CallSignature) { @@ -133,6 +141,8 @@ func (c *Call) Blockly(flags ...bool) ast.Block { return c.listMethods(signature) case "dict": return c.dictMethods(signature) + case "matrix": + return c.matrixMethods(signature) default: panic("Unknown module " + signature.Module) } diff --git a/lang/code/ast/method/matrix.go b/lang/code/ast/method/matrix.go new file mode 100644 index 00000000..ca7488c7 --- /dev/null +++ b/lang/code/ast/method/matrix.go @@ -0,0 +1,60 @@ +package method + +import "Falcon/code/ast" + +func (c *Call) matrixMethods(signature *CallSignature) ast.Block { + switch signature.BlocklyName { + case "matrices_get_row": + return c.matrixGetRow() + case "matrices_get_column": + return c.matrixGetColumn() + case "matrices_get_dims": + return c.matrixGetDimensions() + case "matrices_operations": + return c.matrixOperations() + default: + panic("Unknown matrix method: " + signature.BlocklyName) + } +} + +func (c *Call) matrixOperations() ast.Block { + var blocklyOp string + switch c.Name { + case "inverse": + blocklyOp = "INVERSE" + case "transpose": + blocklyOp = "TRANSPOSE" + case "rotateLeft": + blocklyOp = "ROTATE_LEFT" + case "rotateRight": + blocklyOp = "ROTATE_RIGHT" + default: + panic("Unknown matrix operation: " + c.Name) + } + return ast.Block{ + Type: "matrices_operations", + Fields: []ast.Field{{Name: "OP", Value: blocklyOp}}, + Values: []ast.Value{{Name: "MATRIX", Block: c.On.Blockly()}}, + } +} + +func (c *Call) matrixGetDimensions() ast.Block { + return ast.Block{ + Type: "matrices_get_dims", + Values: []ast.Value{{Name: "MATRIX", Block: c.On.Blockly()}}, + } +} + +func (c *Call) matrixGetRow() ast.Block { + return ast.Block{ + Type: "matrices_get_row", + Values: ast.MakeValueArgs(c.On, "MATRIX", c.Args, "ROW"), + } +} + +func (c *Call) matrixGetColumn() ast.Block { + return ast.Block{ + Type: "matrices_get_column", + Values: ast.MakeValueArgs(c.On, "MATRIX", c.Args, "COLUMN"), + } +} diff --git a/lang/code/parsers/blocklytomist/parser.go b/lang/code/parsers/blocklytomist/parser.go index 15890ed7..072a438c 100644 --- a/lang/code/parsers/blocklytomist/parser.go +++ b/lang/code/parsers/blocklytomist/parser.go @@ -216,6 +216,34 @@ func (p *Parser) parseBlock(block ast.Block) ast.Expr { case "math_convert_angles": return p.mathConvertAngles(block) + case "matrices_create": // todo: we need to be able to form the matrix block from syntax (currently can't!, only lists) + return p.matricesCreate(block) + case "matrices_create_multidim": + return p.matricesNdArray(block) + case "matrices_get_cell": + return p.matricesGetCell(block) // todo: same, we need to preserve matrix reconversion at the end using comment blocks + case "matrices_set_cell": + return p.matricesSetCell(block) // todo: same thing + case "matrices_get_row": + return p.matricesGetRow(block) // we are done + case "matrices_get_column": + return p.matricesGetColumn(block) // we are done + case "matrices_get_dims": + return p.matricesGetDimension(block) // we are done + case "matrices_is_matrix": + return p.makeQuestion(lex.OpenSquare, block, "matrix") + case "matrices_add": + return p.makeBinary("+", p.fromMinVals(block.Values, 2)) + case "matrices_subtract": + return p.makeBinary("-", p.fromMinVals(block.Values, 2)) + case "matrices_multiply": + return p.makeBinary("*", p.fromMinVals(block.Values, 2)) + case "matrices_power": + return p.makeBinary("^", p.fromMinVals(block.Values, 2)) + + case "matrices_operations": + return p.matricesOperations(block) // we are done + case "lists_create_with": return &fundamentals.List{Elements: p.fromMinVals(block.Values, 0)} case "lists_add_items": @@ -947,6 +975,92 @@ func (p *Parser) textCompare(block ast.Block) ast.Expr { return p.makeBinary(pOperation, p.fromMinVals(block.Values, 2)) } +func (p *Parser) matricesGetRow(block ast.Block) ast.Expr { + pVals := p.makeValueMap(block.Values) + return &method.Call{ + Where: lex.MakeFakeToken(lex.OpenSquare), + On: pVals.get("MATRIX"), + Name: "row", + Args: []ast.Expr{pVals.get("ROW")}, + } +} + +func (p *Parser) matricesGetDimension(block ast.Block) ast.Expr { + pVals := p.makeValueMap(block.Values) + return &method.Call{ + Where: lex.MakeFakeToken(lex.OpenSquare), + On: pVals.get("MATRIX"), + Name: "dimension", + Args: []ast.Expr{}, + } +} + +func (p *Parser) matricesGetColumn(block ast.Block) ast.Expr { + pVals := p.makeValueMap(block.Values) + return &method.Call{ + Where: lex.MakeFakeToken(lex.OpenSquare), + On: pVals.get("MATRIX"), + Name: "col", + Args: []ast.Expr{pVals.get("COLUMN")}, + } +} + +func (p *Parser) matricesSetCell(block ast.Block) ast.Expr { + numItems := block.Mutation.ItemCount + pVals := p.makeValueMap(block.Values) + + matrix := pVals.get("MATRIX") + var currHead ast.Expr + currHead = matrix + + for i := 0; i < numItems-1; i++ { + dim := pVals.get("DIM" + strconv.Itoa(i)) + currHead = &list.Get{List: currHead, Index: dim} + } + return &list.Set{List: currHead, Index: pVals.get("DIM" + strconv.Itoa(numItems-1)), Value: pVals.get("VALUE")} +} + +func (p *Parser) matricesGetCell(block ast.Block) ast.Expr { + numItems := block.Mutation.ItemCount + pVals := p.makeValueMap(block.Values) + + matrix := pVals.get("MATRIX") + var currHead ast.Expr + currHead = matrix + + for i := 0; i < numItems; i++ { + dim := pVals.get("DIM" + strconv.Itoa(i)) + currHead = &list.Get{List: currHead, Index: dim} + } + return currHead +} + +func (p *Parser) matricesNdArray(block ast.Block) ast.Expr { + pVals := p.makeValueMap(block.Values) + return common.MakeFuncCall("makeNdArray", pVals.get("DIM"), pVals.get("INITIAL")) +} + +func (p *Parser) matricesCreate(block ast.Block) ast.Expr { + pFields := p.makeFieldMap(block.Fields) + numRows, err := strconv.Atoi(pFields["ROWS"]) + if err != nil { + panic(err) + } + numCols, err := strconv.Atoi(pFields["COLS"]) + if err != nil { + panic(err) + } + matrix := make([]ast.Expr, numRows) + for i := range matrix { + row := make([]ast.Expr, numCols) + for j := range row { + row[j] = &fundamentals.Number{Content: pFields["MATRIX_"+strconv.Itoa(i)+"_"+strconv.Itoa(j)]} + } + matrix[i] = &fundamentals.List{Elements: row} + } + return &fundamentals.List{Elements: matrix} +} + func (p *Parser) mathConvertAngles(block ast.Block) ast.Expr { var funcName string switch block.SingleField() { @@ -1093,6 +1207,29 @@ func (p *Parser) makeColor(block ast.Block) ast.Expr { return &fundamentals.Color{Where: lex.MakeFakeToken(lex.ColorCode), Hex: block.SingleField()} } +func (p *Parser) matricesOperations(block ast.Block) ast.Expr { + var matrixMethod string + switch block.SingleField() { + case "INVERSE": + matrixMethod = "inverse" + case "TRANSPOSE": + matrixMethod = "transpose" + case "ROTATE_LEFT": + matrixMethod = "rotateLeft" + case "ROTATE_RIGHT": + matrixMethod = "rotateRight" + default: + panic("Unknown matrix operation type: " + block.SingleField()) + } + pVals := p.makeValueMap(block.Values) + return &method.Call{ + Where: lex.MakeFakeToken(lex.OpenSquare), + On: pVals.get("MATRIX"), + Name: matrixMethod, + Args: []ast.Expr{}, + } +} + func (p *Parser) makeQuestion(t lex.Type, on ast.Block, name string) ast.Expr { return &common.Question{Where: lex.MakeFakeToken(t), On: p.singleExpr(on), Question: name} } diff --git a/testing/hi.mist b/testing/hi.mist index 69bda836..8f81487e 100644 --- a/testing/hi.mist +++ b/testing/hi.mist @@ -1,14 +1 @@ -@Button { Button1 } -@Label { Label1 } - -func main() { - println("Hello, World!") - println("Counter is currently: " _ this.counter) -} - -global counter = 0 - -when Button1.Click { - this.counter = this.counter + 1 - Label1.Text = counter -} +[[1, 2], [3, 4]].rotateLeft() \ No newline at end of file