项目作者: MarioAriasC

项目描述 :
Monkey implementation
高级语言: Go
项目地址: git://github.com/MarioAriasC/monkey.git
创建时间: 2021-04-25T02:14:02Z
项目社区:https://github.com/MarioAriasC/monkey

开源协议:

下载


Monkey

A go implementation of the Monkey Language

Following both books, it implements the interpreter and the compiler

My code is shorter as I used high order functions in some places to reduce code duplication, i.e.:

Original

  1. var builtins = map[string]*object.Builtin{
  2. "len": &object.Builtin{Fn: func(args ...object.Object) object.Object {
  3. if len(args) != 1 {
  4. return newError("wrong number of arguments. got=%d, want=1",
  5. len(args))
  6. }
  7. switch arg := args[0].(type) {
  8. case *object.Array:
  9. return &object.Integer{Value: int64(len(arg.Elements))}
  10. case *object.String:
  11. return &object.Integer{Value: int64(len(arg.Value))}
  12. default:
  13. return newError("argument to `len` not supported, got %s",
  14. args[0].Type())
  15. }
  16. },
  17. },
  18. "first": &object.Builtin{
  19. Fn: func(args ...object.Object) object.Object {
  20. if len(args) != 1 {
  21. return newError("wrong number of arguments. got=%d, want=1",
  22. len(args))
  23. }
  24. if args[0].Type() != object.ARRAY_OBJ {
  25. return newError("argument to `first` must be ARRAY, got %s",
  26. args[0].Type())
  27. }
  28. arr := args[0].(*object.Array)
  29. if len(arr.Elements) > 0 {
  30. return arr.Elements[0]
  31. }
  32. return NULL
  33. },
  34. },
  35. "last": &object.Builtin{
  36. Fn: func(args ...object.Object) object.Object {
  37. if len(args) != 1 {
  38. return newError("wrong number of arguments. got=%d, want=1",
  39. len(args))
  40. }
  41. if args[0].Type() != object.ARRAY_OBJ {
  42. return newError("argument to `last` must be ARRAY, got %s",
  43. args[0].Type())
  44. }
  45. arr := args[0].(*object.Array)
  46. length := len(arr.Elements)
  47. if length > 0 {
  48. return arr.Elements[length-1]
  49. }
  50. return NULL
  51. },
  52. },

Refactored

  1. func argSizeCheck(expectedSize int, args []object.Object, body func([]object.Object) object.Object) object.Object {
  2. argsLength := len(args)
  3. if argsLength != expectedSize {
  4. return newError("wrong number of arguments. got=%d, want=1", argsLength)
  5. }
  6. return body(args)
  7. }
  8. func arrayCheck(builtinName string, args []object.Object, body func(*object.Array, int) object.Object) object.Object {
  9. if args[0].Type() != object.ArrayObj {
  10. return newError("argument to `%s` must be ARRAY, got %s", builtinName, args[0].Type())
  11. }
  12. arr := args[0].(*object.Array)
  13. return body(arr, len(arr.Elements))
  14. }
  15. var builtins = map[string]*object.Builtin{
  16. "len": {
  17. Fn: func(args ...object.Object) object.Object {
  18. return argSizeCheck(1, args, func(args []object.Object) object.Object {
  19. switch arg := args[0].(type) {
  20. case *object.String:
  21. return &object.Integer{Value: int64(len(arg.Value))}
  22. case *object.Array:
  23. return &object.Integer{Value: int64(len(arg.Elements))}
  24. default:
  25. return newError("argument to `len` not supported, got %s", arg.Type())
  26. }
  27. })
  28. }},
  29. "first": {
  30. Fn: func(args ...object.Object) object.Object {
  31. return argSizeCheck(1, args, func(args []object.Object) object.Object {
  32. return arrayCheck("first", args, func(arr *object.Array, length int) object.Object {
  33. if length > 0 {
  34. return arr.Elements[0]
  35. }
  36. return NULL
  37. })
  38. })
  39. },
  40. },
  41. "last": {
  42. Fn: func(args ...object.Object) object.Object {
  43. return argSizeCheck(1, args, func(args []object.Object) object.Object {
  44. return arrayCheck("last", args, func(arr *object.Array, length int) object.Object {
  45. if length > 0 {
  46. return arr.Elements[length-1]
  47. }
  48. return NULL
  49. })
  50. })
  51. },
  52. },

Running

Build the executable with:

  1. $ go build -o monkey .

And run it with:

  1. $ ./monkey

Benchmarks

Build the benchmark with:

  1. $ go build -o fibonacci ./benchmark

And run it with:

  1. $ ./fibonacci

You can pass two additional parameters:

  • engine with two possible values: vm and eval.
  • algo with two possible values: slow and fast.
  1. $ ./fibonacci --engine=eval

Tests

Run the tests with:

  1. $ go test ./...