dagon 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/.gitignore +2 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README.md +86 -0
  6. data/Rakefile +40 -0
  7. data/bin/dagon +44 -0
  8. data/bin/dspec +35 -0
  9. data/bin/idg +15 -0
  10. data/bin/idgr +16 -0
  11. data/build/parser.rb +1015 -0
  12. data/build/scanner.rb +686 -0
  13. data/core/array.rb +64 -0
  14. data/core/block.rb +38 -0
  15. data/core/class.rb +91 -0
  16. data/core/false.rb +38 -0
  17. data/core/float.rb +93 -0
  18. data/core/frame.rb +24 -0
  19. data/core/hash.rb +51 -0
  20. data/core/integer.rb +98 -0
  21. data/core/object.rb +50 -0
  22. data/core/string.rb +57 -0
  23. data/core/true.rb +37 -0
  24. data/core/vm.rb +125 -0
  25. data/core/void.rb +37 -0
  26. data/dagon.gemspec +19 -0
  27. data/dagon.vim +45 -0
  28. data/dagon/ast/array_node.rb +17 -0
  29. data/dagon/ast/assignment_node.rb +21 -0
  30. data/dagon/ast/block_node.rb +19 -0
  31. data/dagon/ast/class_definition_node.rb +24 -0
  32. data/dagon/ast/constant_ref_node.rb +15 -0
  33. data/dagon/ast/frame.rb +23 -0
  34. data/dagon/ast/function_call_node.rb +33 -0
  35. data/dagon/ast/function_definition_node.rb +15 -0
  36. data/dagon/ast/function_node.rb +23 -0
  37. data/dagon/ast/hash_node.rb +16 -0
  38. data/dagon/ast/if_node.rb +20 -0
  39. data/dagon/ast/instance_init_node.rb +28 -0
  40. data/dagon/ast/instance_var_ref_node.rb +21 -0
  41. data/dagon/ast/literal_node.rb +23 -0
  42. data/dagon/ast/node.rb +22 -0
  43. data/dagon/ast/root_node.rb +19 -0
  44. data/dagon/ast/string_node.rb +16 -0
  45. data/dagon/ast/unary_function_call_node.rb +17 -0
  46. data/dagon/ast/var_ref_node.rb +19 -0
  47. data/dagon/ast/while_node.rb +17 -0
  48. data/dagon/parser.y +151 -0
  49. data/dagon/scanner.rl +143 -0
  50. data/examples/assert.dg +8 -0
  51. data/examples/assignment.dg +2 -0
  52. data/examples/block.dg +8 -0
  53. data/examples/class.dg +6 -0
  54. data/examples/conditional.dg +3 -0
  55. data/examples/conditions.dg +6 -0
  56. data/examples/equality.dg +6 -0
  57. data/examples/error.dg +1 -0
  58. data/examples/eval.dg +1 -0
  59. data/examples/fibonacci.dg +15 -0
  60. data/examples/greeter.dg +6 -0
  61. data/examples/input.dg +3 -0
  62. data/examples/instance_variables.dg +11 -0
  63. data/examples/iterate.dg +2 -0
  64. data/examples/method_call.dg +9 -0
  65. data/examples/method_definition.dg +4 -0
  66. data/examples/operators.dg +6 -0
  67. data/examples/output.dg +1 -0
  68. data/examples/require.dg +1 -0
  69. data/spec/array_spec.dg +26 -0
  70. data/spec/assertions.dg +11 -0
  71. data/spec/boolean_spec.dg +48 -0
  72. data/spec/dspec.dg +16 -0
  73. data/spec/float_spec.dg +15 -0
  74. data/spec/hash_spec.dg +6 -0
  75. data/spec/number_spec.dg +18 -0
  76. data/spec/return_spec.dg +12 -0
  77. data/spec/string_spec.dg +18 -0
  78. data/spec/void_spec.dg +9 -0
  79. data/spec/while_spec.dg +7 -0
  80. metadata +180 -0
@@ -0,0 +1,50 @@
1
+ require "core/class"
2
+
3
+ module Dagon
4
+ module Core
5
+ class DG_Object
6
+ attr_reader :klass
7
+ def initialize klass = nil
8
+ @ivars = {}
9
+ @klass = klass || DG_Class.new
10
+ end
11
+
12
+ def dagon_define_class name, parent
13
+ name = name.to_sym
14
+ klass = DG_Class.new(name, parent)
15
+ @klass.dagon_const_set(name, klass)
16
+ klass
17
+ end
18
+
19
+ def dagon_const_set constant, value
20
+ @klass.dagon_const_set(constant, value)
21
+ end
22
+
23
+ def dagon_const_get constant
24
+ @klass.dagon_const_get(constant)
25
+ end
26
+
27
+ def dagon_send interpreter, name, *args
28
+ method = @klass.get_method(name)
29
+ if method
30
+ frame = Frame.new(self, self)
31
+ interpreter.push_frame frame
32
+ return_value = method.call(interpreter, self, *args) || Dvoid
33
+ interpreter.pop_frame
34
+ return_value
35
+ else
36
+ $stderr.puts "undefined method '#{name}' for #{self.inspect}:#{self.klass.name}"
37
+ exit(1)
38
+ end
39
+ end
40
+
41
+ def set_instance_variable name, value
42
+ @ivars[name.to_sym] = value
43
+ end
44
+
45
+ def get_instance_variable name
46
+ @ivars[name.to_sym]
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,57 @@
1
+ module Dagon
2
+ module Core
3
+ class DG_String < DG_Object
4
+ attr_reader :value
5
+ def initialize value, klass
6
+ @value = value
7
+ @klass = klass
8
+ end
9
+
10
+ def == other
11
+ value == other.value
12
+ end
13
+
14
+ def to_s
15
+ @value
16
+ end
17
+
18
+ def inspect
19
+ %{"#{@value}"}
20
+ end
21
+ end
22
+
23
+ class DG_StringClass < DG_Class
24
+ def initialize
25
+ super("String", Dagon::Core::DG_Class.new)
26
+ end
27
+
28
+ def boot
29
+ add_method "init", ->(vm, ref, value) {
30
+ ref.instance_variable_set("@value", value)
31
+ }
32
+ add_method "+", ->(vm, ref, other) {
33
+ dagon_new(vm, ref.value + other.value)
34
+ }
35
+ add_method "=", ->(vm, ref, other) {
36
+ ref.value == other.value ? Dtrue : Dfalse
37
+ }
38
+ add_method "!=", ->(vm, ref, other) {
39
+ ref.value != other.value ? Dtrue : Dfalse
40
+ }
41
+ add_method 'length', ->(vm, ref) {
42
+ vm.get_class("Integer").instance(ref.value.length)
43
+ }
44
+ add_method 'to-i', ->(vm, ref) {
45
+ vm.get_class("Integer").instance(ref.value.to_i)
46
+ }
47
+ add_method 'to-f', ->(vm, ref) {
48
+ vm.get_class("Float").instance(ref.value.to_f)
49
+ }
50
+ end
51
+
52
+ def dagon_new interpreter, string = ""
53
+ DG_String.new(string, self)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,37 @@
1
+ require 'singleton'
2
+
3
+ module Dagon
4
+ module Core
5
+ class True < DG_Object
6
+ include Singleton
7
+ def initialize
8
+ @value = true
9
+ @klass = DG_TrueClass.new
10
+ end
11
+
12
+ def inspect
13
+ "true"
14
+ end
15
+ end
16
+
17
+ class DG_TrueClass < DG_Class
18
+ undef :dagon_new
19
+ def initialize
20
+ super("True", Dagon::Core::DG_Class.new)
21
+ end
22
+
23
+ def boot
24
+ add_method '!@', ->(vm, ref) {
25
+ Dfalse
26
+ }
27
+ add_method '=', ->(vm, ref, other) {
28
+ ref == other ? Dtrue : Dfalse
29
+ }
30
+ add_method '&&', ->(vm, ref, other) { other }
31
+ add_method '||', ->(vm, ref, other) { Dtrue }
32
+ add_method '^', ->(vm, ref, other) { other.dagon_send(vm, "!@") }
33
+ add_method 'to-s', ->(vm, ref) { vm.get_class("String").dagon_new(vm, "true") }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,125 @@
1
+ CORE = %w(object class array block false float frame integer string true void hash)
2
+ CORE.each do |klass|
3
+ require "core/#{klass}"
4
+ end
5
+
6
+ require "pry"
7
+
8
+ module Dagon
9
+ module Core
10
+ class VM
11
+ attr_reader :globals
12
+ def initialize main = nil
13
+ @load_paths = [File.expand_path(".")]
14
+ @required_files = []
15
+ @object = main || Dagon::Core::DG_Object.new
16
+ @stack = []
17
+ @stack.push Frame.new(@object, '(toplevel)')
18
+ @globals = {}
19
+ @classes = {}
20
+ boot_core
21
+ end
22
+
23
+ def boot_core
24
+ add_class("Array", DG_ArrayClass.new)
25
+ add_class("Block", DG_BlockClass.new)
26
+ add_class("False", DG_FalseClass.new)
27
+ add_class("Float", DG_FloatClass.new)
28
+ add_class("Hash", DG_HashClass.new)
29
+ add_class("Integer", DG_IntegerClass.new)
30
+ add_class("String", DG_StringClass.new)
31
+ add_class("True", DG_TrueClass.new)
32
+ add_class("Void", DG_VoidClass.new)
33
+
34
+ unless Kernel.const_defined?("Dtrue")
35
+ Kernel.const_set("Dtrue", Dagon::Core::True.instance)
36
+ end
37
+ unless Kernel.const_defined?("Dfalse")
38
+ Kernel.const_set("Dfalse", Dagon::Core::False.instance)
39
+ end
40
+ unless Kernel.const_defined?("Dvoid")
41
+ Kernel.const_set("Dvoid", Dagon::Core::Void.instance)
42
+ end
43
+ end
44
+
45
+ def current_object
46
+ @stack[0].object
47
+ end
48
+
49
+ def add_class name, klass
50
+ current_object.dagon_const_set(name, klass)
51
+ end
52
+
53
+ def get_class name
54
+ current_object.dagon_const_get(name)
55
+ end
56
+
57
+ def add_load_path path
58
+ unless @load_paths.include? path
59
+ @load_paths << path
60
+ end
61
+ end
62
+
63
+ def frame
64
+ @stack.last
65
+ end
66
+
67
+ def push_frame frame
68
+ @stack.push frame
69
+ @object = frame.object
70
+ end
71
+
72
+ def pop_frame
73
+ @stack.pop
74
+ @object = frame.object
75
+ end
76
+
77
+ def dagon_define_class name, parent
78
+ @object.dagon_define_class name, parent
79
+ end
80
+
81
+ def define_function name, block
82
+ if @object.respond_to? :add_method
83
+ @object.add_method name, block
84
+ else
85
+ @object.klass.add_method name, block
86
+ end
87
+ end
88
+
89
+ def find_file_path filename
90
+ @load_paths.each do |path|
91
+ if File.exists? File.join(path, "#{filename}.dg")
92
+ return File.join(path, "#{filename}.dg")
93
+ end
94
+ end
95
+ nil
96
+ end
97
+
98
+ def load_file filename
99
+ path = find_file_path(filename.value)
100
+ if path
101
+ @required_files << path
102
+ program = File.read(path)
103
+ tokens = Dagon::Scanner.tokenize(program, filename)
104
+ tree = Dagon::Parser.parse(tokens, filename, false)
105
+ tree.evaluate(self)
106
+ Dtrue
107
+ else
108
+ error "No such file or directory - #{filename.value}\n" +
109
+ "Searched: \n" +
110
+ @load_paths.map{ |path| " #{path}"}.join("\n")
111
+ end
112
+ end
113
+
114
+ def loaded? filename
115
+ @required_files.include? filename
116
+ end
117
+
118
+ def error message
119
+ $stderr.puts message
120
+ exit(1)
121
+ end
122
+ end
123
+ end
124
+ end
125
+
@@ -0,0 +1,37 @@
1
+ require 'singleton'
2
+
3
+ module Dagon
4
+ module Core
5
+ class Void < DG_Object
6
+ include Singleton
7
+ def initialize
8
+ @klass = DG_VoidClass.new
9
+ end
10
+
11
+ def to_s
12
+ ""
13
+ end
14
+
15
+ def value # TODO: determine if there is a better way than this for checking equality
16
+ nil
17
+ end
18
+
19
+ def inspect
20
+ "void"
21
+ end
22
+ end
23
+
24
+ class DG_VoidClass < DG_Class
25
+ undef :dagon_new
26
+ def initialize
27
+ super("Void", Dagon::Core::DG_Class.new)
28
+ end
29
+
30
+ def boot
31
+ add_method "=", ->(vm, ref, other) {
32
+ ref == other ? Dtrue : Dfalse
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "dagon"
5
+ gem.version = "0.1.0"
6
+ gem.authors = ["Caleb Thompson", "Matt Mongeau"]
7
+ gem.email = ["cjaysson@gmail.com", "halogenandtoast@gmail.com"]
8
+ gem.description = "The Dagon programming language: whitespace, enumerators, blocks, One Way"
9
+ gem.summary = "The Esoteric Order of Dagon"
10
+ gem.homepage = "https://github.com/calebthompson/dagon"
11
+
12
+ gem.files = `git ls-files`.split($/)
13
+ gem.executables = gem.files.grep(%r{^bin/(dagon|dspec|idgr)}).map{ |f| File.basename(f) }
14
+ gem.require_paths = %w{core dagon}
15
+
16
+ gem.add_development_dependency 'rake'
17
+ gem.add_development_dependency 'racc'
18
+ gem.add_development_dependency 'pry'
19
+ end
@@ -0,0 +1,45 @@
1
+ " Vim syntax file
2
+ " Language: Dagon
3
+ " Maintainer: Caleb Thompson
4
+ " Latest Revision: 16 January 2013
5
+
6
+ au BufRead,BufNewFile *.dg set filetype=dagon
7
+
8
+ if exists("b:current_syntax")
9
+ finish
10
+ endif
11
+
12
+ syntax keyword dagonConditional if elseif else while break
13
+ syntax keyword dagonBoolean true false
14
+ syntax keyword dagonKeyword void
15
+ syntax keyword dagonFunction print puts
16
+ syntax match dagonNumber '\d'
17
+ syntax match dagonFloat '\d+\.\d+'
18
+ syntax region String start="'" end="'"
19
+ syntax region String start='"' end='"'
20
+ syntax region Array start="\[" end="\]"
21
+ syntax match dagonComment "\v#.*$"
22
+ syntax match dagonConstant "\v[A-Z][A-Za-z]*"
23
+ syntax match dagonIdentifier "\v-?[a-z][a-z0-9-]+"
24
+ syntax match dagonFunctionDefinition "\v-?[a-z][a-z0-9-]+:"
25
+ syntax region dagonFunctionDefinitionArgumentList start="\v-?[a-z][a-z0-9-]+\(" end="):"
26
+ syntax region dagonFunctionCall start="\v-?[a-z][a-z0-9-]+\(" end=")"
27
+ syntax match dagonOperator "\v \*\* "
28
+ syntax match dagonOperator "\v \* "
29
+ syntax match dagonOperator "\v / "
30
+ syntax match dagonOperator "\v \+ "
31
+ syntax match dagonOperator "\v - "
32
+ syntax match dagonAssignment ": "
33
+
34
+ highlight link dagonConditional Conditional
35
+ highlight link dagonKeyword Keyword
36
+ highlight link dagonBoolean Boolean
37
+ highlight link dagonIdentifier dagonFunction
38
+ highlight link dagonFunctionDefinition dagonFunction
39
+ highlight link dagonFunction Function
40
+
41
+ highlight link dagonComment Comment
42
+ highlight link dagonOperator Operator
43
+ highlight link dagonConstant Constant
44
+
45
+ let b:current_syntax = "dagon"
@@ -0,0 +1,17 @@
1
+ require 'core/array'
2
+
3
+ module Dagon
4
+ module AST
5
+ class ArrayNode < Node
6
+ def initialize filename, line_number, list
7
+ super filename, line_number
8
+ @list = list
9
+ end
10
+
11
+ def evaluate interpreter
12
+ evaluated_list = @list.map { |item| item.evaluate(interpreter) }
13
+ interpreter.get_class("Array").dagon_new(interpreter, evaluated_list)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module Dagon
2
+ module AST
3
+ class AssignmentNode < Node
4
+ attr_reader :variable_name
5
+ attr_reader :variable_value
6
+ def initialize filename, line_number, variable_name, value
7
+ super filename, line_number
8
+ @variable_name = variable_name
9
+ @variable_value = value
10
+ end
11
+
12
+ def evaluate interpreter
13
+ if variable_name[0] == "@"
14
+ interpreter.frame.object.set_instance_variable(variable_name, value.evaluate(interpreter))
15
+ else
16
+ interpreter.frame[variable_name] = variable_value.evaluate(interpreter)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ require 'core/block'
2
+
3
+ module Dagon
4
+ module AST
5
+
6
+ class BlockNode < Node
7
+ def initialize filename, line_number, statements, arguments
8
+ super filename, line_number
9
+ @statements = statements
10
+ @arguments = arguments
11
+ end
12
+
13
+ def evaluate interpreter
14
+ arguments = @arguments.map(&:variable_name)
15
+ interpreter.get_class("Block").dagon_new(interpreter, @statements, interpreter.frame, arguments)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require 'core/frame'
2
+ require 'core/class'
3
+
4
+ module Dagon
5
+ module AST
6
+ class ClassDefinitionNode < Node
7
+ def initialize filename, line_number, class_name, statements
8
+ super filename, line_number
9
+ @class_name = class_name
10
+ @statements = statements
11
+ end
12
+
13
+ def evaluate interpreter
14
+ klass = interpreter.dagon_define_class @class_name, Dagon::Core::DG_Class.new
15
+ frame = Dagon::Core::Frame.new(klass, klass.name)
16
+ interpreter.push_frame frame
17
+ @statements.each do |statement|
18
+ statement.evaluate interpreter
19
+ end
20
+ interpreter.pop_frame
21
+ end
22
+ end
23
+ end
24
+ end