sweet-lang 0.1.0
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.
- data/bin/sweet +2 -0
- data/lib/interpreter.rb +141 -0
- data/lib/lexer.rb +3 -0
- data/lib/lexer/core.rb +128 -0
- data/lib/lexer/strings.rb +13 -0
- data/lib/lexer/tags.rb +100 -0
- data/lib/nodes.rb +56 -0
- data/lib/parser.rb +673 -0
- data/lib/runtime.rb +7 -0
- data/lib/runtime/bootstrap.rb +41 -0
- data/lib/runtime/class.rb +43 -0
- data/lib/runtime/context.rb +24 -0
- data/lib/runtime/method.rb +19 -0
- data/lib/runtime/object.rb +18 -0
- data/lib/sweet.rb +28 -0
- metadata +64 -0
data/lib/runtime.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Bootstrap the runtime. This is where we assemble all the classes and objects together
|
2
|
+
# to form the runtime.
|
3
|
+
# What's happening in the runtime:
|
4
|
+
sweet_class = SweetClass.new # Class
|
5
|
+
sweet_class.runtime_class = sweet_class # Class.class = Class
|
6
|
+
object_class = SweetClass.new # Object = Class.new
|
7
|
+
object_class.runtime_class = sweet_class # Object.class = Class
|
8
|
+
|
9
|
+
# Create the Runtime object (the root context) on which all code will start its
|
10
|
+
# evaluation.
|
11
|
+
Runtime = Context.new(object_class.new)
|
12
|
+
|
13
|
+
Runtime["Class"] = sweet_class
|
14
|
+
Runtime["Object"] = object_class
|
15
|
+
Runtime["Number"] = SweetClass.new
|
16
|
+
Runtime["String"] = SweetClass.new
|
17
|
+
|
18
|
+
# Everything is an object in our language, even true, false and nil. So they need
|
19
|
+
# to have a class too.
|
20
|
+
Runtime["TrueClass"] = SweetClass.new
|
21
|
+
Runtime["FalseClass"] = SweetClass.new
|
22
|
+
Runtime["NilClass"] = SweetClass.new
|
23
|
+
|
24
|
+
Runtime["true"] = Runtime["TrueClass"].new_with_value(true)
|
25
|
+
Runtime["false"] = Runtime["FalseClass"].new_with_value(false)
|
26
|
+
Runtime["nil"] = Runtime["NilClass"].new_with_value(nil)
|
27
|
+
|
28
|
+
# Add a few core methods to the runtime.
|
29
|
+
|
30
|
+
# Add the `new` method to classes, used to instantiate a class:
|
31
|
+
# eg.: Object.new, Number.new, String.new, etc.
|
32
|
+
Runtime["Class"].runtime_methods["new"] = proc do |receiver, arguments|
|
33
|
+
receiver.new
|
34
|
+
end
|
35
|
+
|
36
|
+
# Print an object to the console.
|
37
|
+
# eg.: print("hi there!")
|
38
|
+
Runtime["Object"].runtime_methods["print"] = proc do |receiver, arguments|
|
39
|
+
@code << arguments.first.ruby_value
|
40
|
+
Runtime["nil"]
|
41
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Represents a Sweet class in the Ruby world. Classes are objects in Sweet so they
|
2
|
+
# inherit from SweetObject.
|
3
|
+
class SweetClass < SweetObject
|
4
|
+
attr_reader :runtime_methods
|
5
|
+
|
6
|
+
# Creates a new class. Number is an instance of Class for example.
|
7
|
+
def initialize
|
8
|
+
@runtime_methods = {}
|
9
|
+
|
10
|
+
# Check if we're bootstrapping (launching the runtime). During this process the
|
11
|
+
# runtime is not fully initialized and core classes do not yet exists, so we defer
|
12
|
+
# using those once the language is bootstrapped.
|
13
|
+
# This solves the chicken-or-the-egg problem with the Class class. We can
|
14
|
+
# initialize Class then set Class.class = Class.
|
15
|
+
if defined?(Runtime)
|
16
|
+
runtime_class = Runtime["Class"]
|
17
|
+
else
|
18
|
+
runtime_class = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
super(runtime_class)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Lookup a method
|
25
|
+
def lookup(method_name)
|
26
|
+
method = @runtime_methods[method_name]
|
27
|
+
unless method
|
28
|
+
raise "Method not found: #{method_name}"
|
29
|
+
end
|
30
|
+
method
|
31
|
+
end
|
32
|
+
|
33
|
+
# Create a new instance of this class
|
34
|
+
def new
|
35
|
+
SweetObject.new(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Create an instance of this Sweet class that holds a Ruby value. Like a String,
|
39
|
+
# Number or true.
|
40
|
+
def new_with_value(value)
|
41
|
+
SweetObject.new(self, value)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# The evaluation context.
|
2
|
+
class Context
|
3
|
+
attr_reader :locals, :current_self, :current_class
|
4
|
+
|
5
|
+
# We store constants as class variable (class variables start with @@ and instance
|
6
|
+
# variables start with @ in Ruby) since they are globally accessible. If you want to
|
7
|
+
# implement namespacing of constants, you could store it in the instance of this
|
8
|
+
# class.
|
9
|
+
@@constants = {}
|
10
|
+
|
11
|
+
def initialize(current_self, current_class=current_self.runtime_class)
|
12
|
+
@locals = {}
|
13
|
+
@current_self = current_self
|
14
|
+
@current_class = current_class
|
15
|
+
end
|
16
|
+
|
17
|
+
# Shortcuts to access constants, Runtime[...] instead of Runtime.constants[...]
|
18
|
+
def [](name)
|
19
|
+
@@constants[name]
|
20
|
+
end
|
21
|
+
def []=(name, value)
|
22
|
+
@@constants[name] = value
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Represents a method defined in the runtime.
|
2
|
+
class SweetMethod
|
3
|
+
def initialize(params, body)
|
4
|
+
@params = params
|
5
|
+
@body = body
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(receiver, arguments)
|
9
|
+
# Create a context of evaluation in which the method will execute.
|
10
|
+
context = Context.new(receiver)
|
11
|
+
|
12
|
+
# Assign arguments to local variables
|
13
|
+
@params.each_with_index do |param, index|
|
14
|
+
context.locals[param] = arguments[index]
|
15
|
+
end
|
16
|
+
|
17
|
+
@body.eval(context)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Represents an Sweet object instance in the Ruby world.
|
2
|
+
class SweetObject
|
3
|
+
attr_accessor :runtime_class, :ruby_value
|
4
|
+
|
5
|
+
# Each object have a class (named runtime_class to prevent errors with Ruby's class
|
6
|
+
# method). Optionaly an object can hold a Ruby value (eg.: numbers and strings).
|
7
|
+
def initialize(runtime_class, ruby_value=self)
|
8
|
+
@runtime_class = runtime_class
|
9
|
+
@ruby_value = ruby_value
|
10
|
+
end
|
11
|
+
|
12
|
+
# Call a method on the object.
|
13
|
+
def call(method, arguments=[])
|
14
|
+
# Like a typical Class-based runtime model, we store methods in the class of the
|
15
|
+
# object.
|
16
|
+
@runtime_class.lookup(method).call(self, arguments)
|
17
|
+
end
|
18
|
+
end
|
data/lib/sweet.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "interpreter"
|
4
|
+
require "readline"
|
5
|
+
|
6
|
+
interpreter = Interpreter.new
|
7
|
+
|
8
|
+
# If a file is given we eval it.
|
9
|
+
if file = ARGV.first
|
10
|
+
@filename = ARGV.first.split(".")[0]
|
11
|
+
File.new("#{@filename}.html", "w")
|
12
|
+
interpreter.eval File.read(file)
|
13
|
+
File.open("#{@filename}.html", 'a') do |f|
|
14
|
+
f.puts @code.join("\n")
|
15
|
+
end
|
16
|
+
puts "Sweet code compiled!"
|
17
|
+
|
18
|
+
# Start the REPL, read-eval-print-loop, or interactive interpreter
|
19
|
+
else
|
20
|
+
puts "Sweet Interactive Console, CTRL+C to quit"
|
21
|
+
loop do
|
22
|
+
line = Readline::readline(">> ")
|
23
|
+
Readline::HISTORY.push(line)
|
24
|
+
value = interpreter.eval(line)
|
25
|
+
puts "=> #{value.ruby_value.inspect}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sweet-lang
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- João Moura
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-13 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! "Sweet is a pre-compiled language based on Ruby and Python. \n Sweet
|
15
|
+
makes possible to use all the class, defs, conditionals, global and \n local
|
16
|
+
variables power of server-side languages, defining blocks by indentation \n like
|
17
|
+
Python in your Sweet HTML markup.\n It comes with a SIC ( Sweet Interactive Console
|
18
|
+
) the you can test your code and ideas\n before really right and compile it."
|
19
|
+
email: joaomdmoura@gmail.com
|
20
|
+
executables:
|
21
|
+
- sweet
|
22
|
+
extensions: []
|
23
|
+
extra_rdoc_files: []
|
24
|
+
files:
|
25
|
+
- lib/sweet.rb
|
26
|
+
- lib/interpreter.rb
|
27
|
+
- lib/lexer.rb
|
28
|
+
- lib/nodes.rb
|
29
|
+
- lib/parser.rb
|
30
|
+
- lib/runtime.rb
|
31
|
+
- lib/lexer/core.rb
|
32
|
+
- lib/lexer/strings.rb
|
33
|
+
- lib/lexer/tags.rb
|
34
|
+
- lib/runtime/bootstrap.rb
|
35
|
+
- lib/runtime/class.rb
|
36
|
+
- lib/runtime/context.rb
|
37
|
+
- lib/runtime/method.rb
|
38
|
+
- lib/runtime/object.rb
|
39
|
+
- bin/sweet
|
40
|
+
homepage: https://github.com/joaomdmoura/sweet
|
41
|
+
licenses: []
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.8.11
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: A Sweet language, that compiles for HTML
|
64
|
+
test_files: []
|