Commit 454bb9d4c2120ff0f7699a35e3ac59bc702012d5
- Diff rendering mode:
- inline
- side by side
README
(7 / 3)
|   | |||
| 33 | 33 | * Support for debug output via: bin/stackd filename.stackd --debug | |
| 34 | 34 | -> Outputs the parsed AST | |
| 35 | 35 | ||
| 36 | What's partially implemented: | ||
| 37 | * A generic object system (as in Factor) | ||
| 38 | * Support for: | ||
| 39 | * Generic Words & Methods | ||
| 40 | * Inheritance | ||
| 41 | |||
| 36 | 42 | What's still missing (and never might be implemented): | |
| 37 | |||
| 43 | * Private / read-only slots on objects / classes (and probably more) | ||
| 38 | 44 | * Nice development tools, as Factor has them | |
| 39 | 45 | * Real debugger or walker | |
| 40 | * An generic object system (as in Factor) | ||
| 41 | 46 | * Many more features, you'll find in Factor | |
| 42 | |||
| 43 | 47 | ||
| 44 | 48 | Some basic syntax rules: | |
| 45 | 49 | * All expressions / statements need to end with a semicolon (';') |
examples/generics.stackd
(22 / 7)
|   | |||
| 1 | 1 | use: core.math core.misc ; | |
| 2 | 2 | in: examples.generics ; | |
| 3 | 3 | ||
| 4 | tuple: shape ; | ||
| 4 | tuple: shape name ; | ||
| 5 | 5 | ||
| 6 | tuple: rectangle height width ; | ||
| 7 | tuple: circle delimiter ; | ||
| 6 | tuple: rectangle < shape height width ; | ||
| 7 | tuple: circle < shape delimiter ; | ||
| 8 | 8 | ||
| 9 | 9 | generic: area ; !( shape -- area ) | |
| 10 | 10 | ||
| … | … | ||
| 12 | 12 | [ height>> ] [ width>> ] bi * ; | |
| 13 | 13 | ||
| 14 | 14 | : <rectangle> | |
| 15 | rectangle new ; | ||
| 15 | rectangle new "RECTANGLE" >>name ; | ||
| 16 | 16 | ||
| 17 | 17 | m: circle area | |
| 18 | 18 | delimiter>> sq core.math::PI * ; | |
| 19 | 19 | ||
| 20 | 20 | : <circle> | |
| 21 | circle new ; | ||
| 21 | circle new "CIRCLE" >>name ; | ||
| 22 | 22 | ||
| 23 | <rectangle> 10 >>height 10 >>width area print ; | ||
| 23 | generic: print-name ; ! ( shape -- ) | ||
| 24 | ! a method only defined on shape | ||
| 25 | ! will also work on all subclasses (polymorphism) :) | ||
| 26 | ! actually, since Stackd is dynamic, it will work on any | ||
| 27 | ! datatype that has a name slot. | ||
| 28 | m: shape print-name | ||
| 29 | "Shape: " print- name>> print ; | ||
| 24 | 30 | ||
| 25 | <circle> 10 >>delimiter area print ; | ||
| 31 | <rectangle> | ||
| 32 | 10 >>height | ||
| 33 | 10 >>width | ||
| 34 | [ print-name ] keep | ||
| 35 | "-- Area: " print- area print ; | ||
| 36 | |||
| 37 | <circle> | ||
| 38 | 10 >>delimiter | ||
| 39 | [ print-name ] keep | ||
| 40 | "-- Area: " print- area print ; |
runtime/primitives/syntax.rb
(7 / 3)
|   | |||
| 33 | 33 | syntax('tuple:') do |scope, atoms| | |
| 34 | 34 | tuplename = atoms.first.text_value | |
| 35 | 35 | slots = atoms.rest.map{|a| a.text_value} | |
| 36 | superclass = nil | ||
| 36 | 37 | case atoms.first | |
| 37 | 38 | when Stackd::Identifier | |
| 38 | 39 | mod = get_current_module(scope) | |
| 39 | 40 | if mod | |
| 40 | mod.define_tuple(tuplename, slots) | ||
| 41 | else | ||
| 42 | scope.define_tuple(tuplename, slots) | ||
| 41 | scope = mod | ||
| 43 | 42 | end | |
| 43 | if slots[0] == "<" | ||
| 44 | superclass = scope[slots[1]] | ||
| 45 | slots = slots[2..-1] | ||
| 46 | end | ||
| 47 | scope.define_tuple(tuplename, slots, superclass) | ||
| 44 | 48 | end | |
| 45 | 49 | end | |
| 46 | 50 |
runtime/scope.rb
(2 / 2)
|   | |||
| 34 | 34 | self[name] = Syntax.new(self, &block) | |
| 35 | 35 | end | |
| 36 | 36 | ||
| 37 | def define_tuple(name, slots) | ||
| 38 | tuple = Tuple.new(name, slots) | ||
| 37 | def define_tuple(name, slots, superclass = nil) | ||
| 38 | tuple = Tuple.new(name, slots, superclass) | ||
| 39 | 39 | self.tuples[name] = tuple | |
| 40 | 40 | define_slot_accessors(slots) | |
| 41 | 41 | self[name] = tuple |
runtime/tuple.rb
(13 / 4)
|   | |||
| 1 | 1 | class Tuple | |
| 2 | attr_reader :slots, :name | ||
| 3 | def initialize(name, slots) | ||
| 2 | attr_reader :slots, :name, :superclass | ||
| 3 | def initialize(name, slots, superclass = nil) | ||
| 4 | 4 | @name = name | |
| 5 | @slots = slots || [] | ||
| 5 | if superclass | ||
| 6 | @superclass = superclass | ||
| 7 | @slots = superclass.slots # inherits from superclass | ||
| 8 | else | ||
| 9 | @slots = [] | ||
| 10 | end | ||
| 11 | @slots += slots | ||
| 12 | @slots.uniq! # no double slotnames | ||
| 6 | 13 | @instances = [] | |
| 7 | 14 | end | |
| 8 | 15 | ||
| 9 | 16 | def to_s | |
| 10 | "#<Tuple:#{@name} [#{@slots.join(',')}]>" | ||
| 17 | superclass_str = "" | ||
| 18 | superclass_str = "< #{@superclass.name} " if @superclass | ||
| 19 | "#<Tuple:#{@name} #{superclass_str}[#{@slots.join(',')}]>" | ||
| 11 | 20 | end | |
| 12 | 21 | ||
| 13 | 22 | def inspect |
runtime/word.rb
(14 / 1)
|   | |||
| 46 | 46 | @implementations = {} # Hash with tuples as keys | |
| 47 | 47 | end | |
| 48 | 48 | ||
| 49 | def get_method_implementation(tuple) | ||
| 50 | impl = @implementations[tuple] | ||
| 51 | unless impl | ||
| 52 | if tuple.superclass | ||
| 53 | get_method_implementation(tuple.superclass) | ||
| 54 | else | ||
| 55 | nil | ||
| 56 | end | ||
| 57 | else | ||
| 58 | impl | ||
| 59 | end | ||
| 60 | end | ||
| 61 | |||
| 49 | 62 | def call(scope) | |
| 50 | 63 | obj = DS.peek # last element (top of stack) is our dispatch object | |
| 51 | 64 | if obj.is_a?(TupleInstance) # only call generic words on tuple instances | |
| 52 | impl = @implementations[obj.tuple] | ||
| 65 | impl = get_method_implementation(obj.tuple) | ||
| 53 | 66 | if impl | |
| 54 | 67 | impl.call(scope) | |
| 55 | 68 | else |

