turmali 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ require "turmali/runtime/class"
2
+ # First, we create a Ruby Hash in which we'll store all constants accessible from inside
3
+ # our runtime.
4
+ # Then, we populate this Hash with the core classes of our language.
5
+ Constants = {}
6
+
7
+ Constants["Class"] = TurmaliClass.new # Defining the `Class` class.
8
+ Constants["Class"].runtime_class = Constants["Class"] # Setting `Class.class = Class`.
9
+ Constants["Object"] = TurmaliClass.new # Defining the `Object` class
10
+ Constants["Number"] = TurmaliClass.new # Defining the `Number` class
11
+ Constants["String"] = TurmaliClass.new
12
+
13
+ # The root context will be the starting point where all our programs will
14
+ # start their evaluation. This will also set the value of `self` at the root
15
+ # of our programs.
16
+ root_self = Constants["Object"].new
17
+ RootContext = Context.new(root_self)
18
+
19
+ # Everything is an object in our language, even `true`, `false` and `nil`. So they need
20
+ # to have a class too.
21
+ Constants["TrueClass"] = TurmaliClass.new
22
+ Constants["FalseClass"] = TurmaliClass.new
23
+ Constants["NilClass"] = TurmaliClass.new
24
+
25
+ Constants["true"] = Constants["TrueClass"].new_with_value(true)
26
+ Constants["false"] = Constants["FalseClass"].new_with_value(false)
27
+ Constants["nil"] = Constants["NilClass"].new_with_value(nil)
28
+
29
+ # Now that we have injected all the core classes into the runtime, we can define
30
+ # methods on those classes.
31
+ #
32
+ # The first method we'll define will allow us to do `Object.new` or
33
+ # `Number.new`. Keep in mind, `Object` or `Number`
34
+ # are instances of the `Class` class. By defining the `new` method
35
+ # on `Class`, it will be accessible on all its instances.
36
+ Constants["Class"].def :new do |receiver, arguments|
37
+ receiver.new
38
+ end
39
+
40
+ # Next, we'll define the `print` method. Since we want to be able to call it
41
+ # from everywhere, we'll define it on `Object`.
42
+ # Remember from the parser's `Call` rule, methods without any receiver will be
43
+ # sent to `self`. So `print()` is the same as `self.print()`, and
44
+ # `self` will always be an instance of `Object`.
45
+ Constants["Object"].def :print do |receiver, arguments|
46
+ puts arguments.first.ruby_value
47
+ Constants["nil"] # We always want to return objects from our runtime
48
+ end
@@ -0,0 +1,36 @@
1
+ require "turmali/runtime/object"
2
+ require "turmali/runtime/context"
3
+
4
+ class TurmaliClass < TurmaliObject
5
+ # Classes are objects in Turmali so they inherit from TurmaliObject.
6
+
7
+ attr_reader :runtime_methods
8
+
9
+ def initialize
10
+ @runtime_methods = {}
11
+ @runtime_class = Constants["Class"]
12
+ end
13
+
14
+ # Lookup a method
15
+ def lookup(method_name)
16
+ method = @runtime_methods[method_name]
17
+ raise "Method not found: #{method_name}" if method.nil?
18
+ method
19
+ end
20
+
21
+ # Helper method to define a method on this class from Ruby.
22
+ def def(name, &block)
23
+ @runtime_methods[name.to_s] = block
24
+ end
25
+
26
+ # Create a new instance of this class
27
+ def new
28
+ TurmaliObject.new(self)
29
+ end
30
+
31
+ # Create an instance of this Turmali class that holds a Ruby value. Like a String,
32
+ # Number or true.
33
+ def new_with_value(value)
34
+ TurmaliObject.new(self, value)
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ class Context
2
+ attr_reader :locals, :current_self, :current_class
3
+
4
+ def initialize(current_self, current_class=current_self.runtime_class)
5
+ @locals = {}
6
+ @current_self = current_self
7
+ @current_class = current_class
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ class TurmaliMethod
2
+ def initialize(params, body)
3
+ @params = params
4
+ @body = body
5
+ end
6
+
7
+ def call(receiver, arguments)
8
+ # Create a context of evaluation in which the method will execute.
9
+ context = Context.new(receiver)
10
+
11
+ # Assign passed arguments to local variables.
12
+ @params.each_with_index do |param, index|
13
+ context.locals[param] = arguments[index]
14
+ end
15
+
16
+ # The body is a node (created in the parser).
17
+ # We'll talk in details about the `eval` method in the interpreter chapter.
18
+ @body.eval(context)
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ class TurmaliObject
2
+ # Each object has a class (named <code>runtime_class</code> to prevent conflicts
3
+ # with Ruby's <code>class</code> keyword).
4
+ # Optionally an object can hold a Ruby value. Eg.: numbers and strings will store their
5
+ # number or string Ruby equivalent in that variable.
6
+ attr_accessor :runtime_class, :ruby_value
7
+
8
+ def initialize(runtime_class, ruby_value=self)
9
+ @runtime_class = runtime_class
10
+ @ruby_value = ruby_value
11
+ end
12
+
13
+ # Like a typical Class-based runtime model, we store methods in the class of the
14
+ # object. When calling a method on an object, we need to first lookup that
15
+ # method in the class, and then call it.
16
+ def call(method, arguments=[])
17
+ @runtime_class.lookup(method).call(self, arguments)
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Turmali
2
+ VERSION = "0.0.1"
3
+ end
data/turmali.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "turmali/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "turmali"
8
+ spec.version = Turmali::VERSION
9
+ spec.authors = ["Eiffel Qiu"]
10
+ spec.email = ["eiffelqiu@qq.com"]
11
+
12
+ spec.summary = %q{Turmali is a website building language.}
13
+ spec.description = %q{Turmali is a website building language.}
14
+ spec.homepage = "https://github.com/eiffelqiu/turmali."
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against " \
23
+ "public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "bin"
30
+ spec.executables = 'tml'
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.15"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: turmali
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Eiffel Qiu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: Turmali is a website building language.
56
+ email:
57
+ - eiffelqiu@qq.com
58
+ executables:
59
+ - tml
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".DS_Store"
64
+ - ".gitignore"
65
+ - ".rspec"
66
+ - ".travis.yml"
67
+ - CODE_OF_CONDUCT.md
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - bin/tml
73
+ - lib/.DS_Store
74
+ - lib/turmali.rb
75
+ - lib/turmali/.DS_Store
76
+ - lib/turmali/grammar.y
77
+ - lib/turmali/interpreter.rb
78
+ - lib/turmali/lexer.rb
79
+ - lib/turmali/nodes.rb
80
+ - lib/turmali/parser.rb
81
+ - lib/turmali/runtime/bootstrap.rb
82
+ - lib/turmali/runtime/class.rb
83
+ - lib/turmali/runtime/context.rb
84
+ - lib/turmali/runtime/method.rb
85
+ - lib/turmali/runtime/object.rb
86
+ - lib/turmali/version.rb
87
+ - turmali.gemspec
88
+ homepage: https://github.com/eiffelqiu/turmali.
89
+ licenses:
90
+ - MIT
91
+ metadata:
92
+ allowed_push_host: https://rubygems.org
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.6.11
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Turmali is a website building language.
113
+ test_files: []