turmali 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []