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.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +61 -0
- data/Rakefile +6 -0
- data/bin/tml +31 -0
- data/lib/.DS_Store +0 -0
- data/lib/turmali.rb +2 -0
- data/lib/turmali/.DS_Store +0 -0
- data/lib/turmali/grammar.y +228 -0
- data/lib/turmali/interpreter.rb +156 -0
- data/lib/turmali/lexer.rb +129 -0
- data/lib/turmali/nodes.rb +88 -0
- data/lib/turmali/parser.rb +683 -0
- data/lib/turmali/runtime/bootstrap.rb +48 -0
- data/lib/turmali/runtime/class.rb +36 -0
- data/lib/turmali/runtime/context.rb +9 -0
- data/lib/turmali/runtime/method.rb +20 -0
- data/lib/turmali/runtime/object.rb +19 -0
- data/lib/turmali/version.rb +3 -0
- data/turmali.gemspec +36 -0
- metadata +113 -0
@@ -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,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
|
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: []
|