operators.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package generator
  2. import (
  3. "github.com/jcla1/gisp/parser"
  4. "go/ast"
  5. "go/token"
  6. )
  7. var (
  8. callableOperators = []string{">", ">=", "<", "<=", "=", "+", "-", "*", "/", "mod"}
  9. logicOperatorMap = map[string]token.Token{
  10. "and": token.LAND,
  11. "or": token.LOR,
  12. }
  13. unaryOperatorMap = map[string]token.Token{
  14. "!": token.NOT,
  15. }
  16. )
  17. func isCallableOperator(node *parser.CallNode) bool {
  18. if node.Callee.Type() != parser.NodeIdent {
  19. return false
  20. }
  21. ident := node.Callee.(*parser.IdentNode).Ident
  22. return isInSlice(ident, callableOperators)
  23. }
  24. // We handle comparisons as a call to some go code, since you can only
  25. // compare ints, floats, cmplx, and such, you know...
  26. // We handle arithmetic operations as function calls, since all args are evaluated
  27. func makeNAryCallableExpr(node *parser.CallNode) *ast.CallExpr {
  28. op := node.Callee.(*parser.IdentNode).Ident
  29. args := EvalExprs(node.Args)
  30. var selector string
  31. // TODO: abstract this away into a map!!!
  32. switch op {
  33. case ">":
  34. selector = "GT"
  35. case ">=":
  36. selector = "GTEQ"
  37. case "<":
  38. selector = "LT"
  39. case "<=":
  40. selector = "LTEQ"
  41. case "=":
  42. selector = "EQ"
  43. case "+":
  44. selector = "ADD"
  45. case "-":
  46. selector = "SUB"
  47. case "*":
  48. selector = "MUL"
  49. case "/":
  50. selector = "DIV"
  51. case "mod":
  52. if len(node.Args) > 2 {
  53. panic("can't calculate modulo with more than 2 arguments!")
  54. }
  55. selector = "MOD"
  56. }
  57. return makeFuncCall(makeSelectorExpr(ast.NewIdent("core"), ast.NewIdent(selector)), args)
  58. }
  59. func isLogicOperator(node *parser.CallNode) bool {
  60. if node.Callee.Type() != parser.NodeIdent {
  61. return false
  62. }
  63. _, ok := logicOperatorMap[node.Callee.(*parser.IdentNode).Ident]
  64. if len(node.Args) < 2 && ok {
  65. panic("can't use binary operator with only one argument!")
  66. }
  67. return ok
  68. }
  69. // But logical comparisons are done properly, since those can short-circuit
  70. func makeNAryLogicExpr(node *parser.CallNode) *ast.BinaryExpr {
  71. op := logicOperatorMap[node.Callee.(*parser.IdentNode).Ident]
  72. outer := makeBinaryExpr(op, EvalExpr(node.Args[0]), EvalExpr(node.Args[1]))
  73. for i := 2; i < len(node.Args); i++ {
  74. outer = makeBinaryExpr(op, outer, EvalExpr(node.Args[i]))
  75. }
  76. return outer
  77. }
  78. func makeBinaryExpr(op token.Token, x, y ast.Expr) *ast.BinaryExpr {
  79. return &ast.BinaryExpr{
  80. X: x,
  81. Y: y,
  82. Op: op,
  83. }
  84. }
  85. func isUnaryOperator(node *parser.CallNode) bool {
  86. if node.Callee.Type() != parser.NodeIdent {
  87. return false
  88. }
  89. _, ok := unaryOperatorMap[node.Callee.(*parser.IdentNode).Ident]
  90. if len(node.Args) != 1 && ok {
  91. panic("unary expression takes, exactly, one argument!")
  92. }
  93. return ok
  94. }
  95. func makeUnaryExpr(op token.Token, x ast.Expr) *ast.UnaryExpr {
  96. return &ast.UnaryExpr{
  97. X: x,
  98. Op: op,
  99. }
  100. }
  101. func isInSlice(elem string, slice []string) bool {
  102. for _, el := range slice {
  103. if elem == el {
  104. return true
  105. }
  106. }
  107. return false
  108. }