sweet-lang 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/runtime.rb ADDED
@@ -0,0 +1,7 @@
1
+ @code = []
2
+
3
+ require "runtime/object"
4
+ require "runtime/class"
5
+ require "runtime/method"
6
+ require "runtime/context"
7
+ require "runtime/bootstrap"
@@ -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: []