ast_ast 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +24 -0
- data/LICENSE +20 -0
- data/README.md +51 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/ast_ast.rb +10 -0
- data/lib/ast_ast/ast.rb +5 -0
- data/lib/ast_ast/token.rb +35 -0
- data/lib/ast_ast/tokeniser.rb +95 -0
- data/lib/ast_ast/tokens.rb +69 -0
- data/lib/ast_ast/tree.rb +5 -0
- data/lib/ast_tokens.rb +8 -0
- data/test/helper.rb +10 -0
- data/test/test_ast_ast.rb +5 -0
- data/test/test_tokeniser.rb +13 -0
- metadata +112 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Joshua Hawxwell
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# AstAst
|
2
|
+
|
3
|
+
|
4
|
+
sSSSSs
|
5
|
+
saaAAA Tttttts
|
6
|
+
sa tT t TT tt
|
7
|
+
saaaaaaA t tT t TT Ts
|
8
|
+
sa tt T tT t TT Ts
|
9
|
+
AaaaaaaAaaaaAAt TsssssTs
|
10
|
+
tT t tSTSsssSTt tt
|
11
|
+
t tt t tt
|
12
|
+
/t tt /t tt
|
13
|
+
( t tt ( t tt
|
14
|
+
\t tt \t tt
|
15
|
+
t tt t tt
|
16
|
+
t tt\ t tts
|
17
|
+
S tS.`. S tS ss
|
18
|
+
tsssst-' tsssstSSS
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
__VERY IMPORTANT:__ it is probably a very bad idea to use this in something that relies on it. It will change without warning!
|
24
|
+
|
25
|
+
## Goals/Ideas
|
26
|
+
|
27
|
+
Crazy simple string -> token converting, using regular expression rules and optional blocks. Some of the finer points of this still need working out, mainly should you be able to affect the name of the token within the block.
|
28
|
+
|
29
|
+
class MyTokeniser < Ast::Tokeniser
|
30
|
+
rule :long, /--[a-zA-Z0-9]+/
|
31
|
+
rule :short, /-[a-zA-Z0-9]+/
|
32
|
+
rule :word, /[a-zA-Z0-9]+/
|
33
|
+
end
|
34
|
+
input = "--along -sh aword"
|
35
|
+
MyTokeniser.tokenise(input)
|
36
|
+
#=> #<Ast::Tokens [[:long, "--along"], [:short, "-sh"], [:word, "aword"]]>
|
37
|
+
|
38
|
+
# Use blocks to change results, passes matches
|
39
|
+
class MyTokeniser < Ast::Tokeniser
|
40
|
+
rule :long, /--([a-zA-Z0-9]+)/ {|i| i[1]}
|
41
|
+
rule :short, /-([a-zA-Z0-9]+)/ {|i| i[1].split} # creates an array so splits into multiple tokens
|
42
|
+
rule :word, /[a-zA-Z0-9]+/
|
43
|
+
end
|
44
|
+
input = "--along -sh aword"
|
45
|
+
MyTokeniser.tokenise(input)
|
46
|
+
#=> #<Ast::Tokens [[:long, "along"], [:short, "s"], [:short, "h"], [:word, "aword"]]>
|
47
|
+
|
48
|
+
|
49
|
+
## Copyright
|
50
|
+
|
51
|
+
Copyright (c) 2010 Joshua Hawxwell. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "ast_ast"
|
8
|
+
gem.summary = %Q{String -> Tokens -> AST}
|
9
|
+
gem.description = %Q{Easily convert strings to Tokens and then on to an Abstract Syntax Tree easily. (Very far from finished!)}
|
10
|
+
gem.email = "m@hawx.me"
|
11
|
+
gem.homepage = "http://github.com/hawx/ast_ast"
|
12
|
+
gem.authors = ["Joshua Hawxwell"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
gem.add_development_dependency "yard", ">= 0"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/test_*.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => :check_dependencies
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
begin
|
47
|
+
require 'yard'
|
48
|
+
YARD::Rake::YardocTask.new
|
49
|
+
rescue LoadError
|
50
|
+
task :yardoc do
|
51
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
52
|
+
end
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/lib/ast_ast.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Ast
|
2
|
+
class Token
|
3
|
+
attr_accessor :type, :value
|
4
|
+
|
5
|
+
def initialize(type, value)
|
6
|
+
@type = type.to_sym
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
# Check whether an array given is valid, ie. it has a symbol
|
11
|
+
# then an object only.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# Ast::Token.valid? [:type, 'val'] #=> true
|
16
|
+
# Ast::Token.valid? ['wrong', 'val'] #=> false
|
17
|
+
# Ast::Token.valid? ['too', 'long', 1] #=> false
|
18
|
+
#
|
19
|
+
def self.valid?(arr)
|
20
|
+
if arr.is_a? Array
|
21
|
+
if arr.nil? || arr.size != 2
|
22
|
+
return false
|
23
|
+
elsif !arr[0].is_a?(Symbol)
|
24
|
+
return false
|
25
|
+
else
|
26
|
+
return true
|
27
|
+
end
|
28
|
+
elsif arr.is_a? Ast::Token
|
29
|
+
return true
|
30
|
+
else
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# @abstract
|
2
|
+
module Ast
|
3
|
+
class Tokeniser
|
4
|
+
attr_accessor :rules, :scanner
|
5
|
+
|
6
|
+
# Describes a single rule created within the Ast::Tokeniser subclass
|
7
|
+
class Rule
|
8
|
+
attr_accessor :name, :regex, :block
|
9
|
+
|
10
|
+
# Creates a new Rule instance
|
11
|
+
#
|
12
|
+
# @param [Symbol] name name of the token to be created
|
13
|
+
# @param [Regexp] regex regular expression to be matched
|
14
|
+
# @param [Proc] block optional block to be executed with match(es)
|
15
|
+
def initialize(name, regex, &block)
|
16
|
+
@name = name
|
17
|
+
@regex = regex
|
18
|
+
@block = block || Proc.new {|i| i}
|
19
|
+
end
|
20
|
+
|
21
|
+
# Runs the block that was given using either, the full match if there
|
22
|
+
# were no captures in the regex, or an array of the captures.
|
23
|
+
#
|
24
|
+
# If a String is returned, which will be the case most of the time, a
|
25
|
+
# single token is created with the value that is returned. But if an
|
26
|
+
# Array is returned then multiple tokens will be created for each item
|
27
|
+
# in the Array. See the examples for a better explanation.
|
28
|
+
#
|
29
|
+
# @param [String] val the string that was matched to +@regex+
|
30
|
+
# @return [String, Array]
|
31
|
+
#
|
32
|
+
# @example Single tokens created (returns String)
|
33
|
+
#
|
34
|
+
# class Klass < Ast::Tokeniser
|
35
|
+
# rule(:word, /[a-z]+/) {|i| i.reverse}
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Klass.tokenise("backwards sdrawrof")
|
39
|
+
# #=> [[:word, "sdrawkcab"], [:word, "forwards"]]
|
40
|
+
#
|
41
|
+
# @example Multiple tokens created (returns Array)
|
42
|
+
#
|
43
|
+
# class Klass < Ast::Tokeniser
|
44
|
+
# rule(:letter, /[a-z]+/) {|i| i.split('')}
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# Klass.tokenise("split up")
|
48
|
+
# #=> [[:letter, "s"], [:letter, "p"], [:letter, "l"], [:letter, "i"], [:letter, "t"], [:letter, "u"], [:letter, "p"]]
|
49
|
+
#
|
50
|
+
#
|
51
|
+
def run(val)
|
52
|
+
arr = val.match(@regex).to_a
|
53
|
+
val = arr unless arr.empty?
|
54
|
+
val = arr[0] if arr.size == 1
|
55
|
+
@block.call val
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates a new Rule and adds to the +@rules+ list.
|
60
|
+
# @see Ast::Tokeniser::Rule#initialize
|
61
|
+
def self.rule(name, regex, &block)
|
62
|
+
@rules ||= []
|
63
|
+
@rules << Rule.new(name, regex, &block)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Takes the input and uses the rules that were created to scan it.
|
67
|
+
#
|
68
|
+
# @param [String] input string to scan
|
69
|
+
# @return [Array]
|
70
|
+
def self.tokenise(input)
|
71
|
+
@scanner = StringScanner.new(input)
|
72
|
+
|
73
|
+
result = []
|
74
|
+
until @scanner.eos?
|
75
|
+
@rules.each do |i|
|
76
|
+
a = @scanner.scan(i.regex)
|
77
|
+
unless a.nil?
|
78
|
+
ran = i.run(a)
|
79
|
+
# split array into separate tokens, *not* values
|
80
|
+
if ran.is_a? Array
|
81
|
+
ran.each {|a| result << [i.name, a]}
|
82
|
+
else
|
83
|
+
result << [i.name, ran]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
# obviously no rule matches this so ignore it
|
88
|
+
# could add verbose mode where this throws an exception!
|
89
|
+
@scanner.pos += 1 unless @scanner.eos?
|
90
|
+
end
|
91
|
+
result
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Ast
|
2
|
+
class Tokens < Array
|
3
|
+
|
4
|
+
def <<(val)
|
5
|
+
raise "value given #{val} is invalid" unless Ast::Token.valid?(val)
|
6
|
+
if val.is_a? Array
|
7
|
+
self << Ast::Token.new(val[0], val[1])
|
8
|
+
else
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# @group Enumeration
|
14
|
+
|
15
|
+
alias_method :_each, :each
|
16
|
+
# Loops through the types and contents of each tag separately, passing them
|
17
|
+
# to the block given.
|
18
|
+
#
|
19
|
+
# @return [Ast::Tokens] returns self
|
20
|
+
# @yield [Symbol, Object] gives the type and content of each block in turn
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
#
|
24
|
+
# tokens = Ast::Tokens.new
|
25
|
+
# tokens << [:a, 1] << [:b, 2] << [:c, 3] << [:d, 4]
|
26
|
+
#
|
27
|
+
# sa.each do |t, v|
|
28
|
+
# puts "#{t} -> #{v}"
|
29
|
+
# end
|
30
|
+
# #=> a -> 1
|
31
|
+
# #=> b -> 2
|
32
|
+
# #=> c -> 3
|
33
|
+
# #=> d -> 4
|
34
|
+
#
|
35
|
+
def each(&blck)
|
36
|
+
self._each do |i|
|
37
|
+
yield(i.type, i.value)
|
38
|
+
end
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
# Evalute block given for the type of each token
|
43
|
+
# @see #each
|
44
|
+
def each_type(&blck)
|
45
|
+
self._each do |i|
|
46
|
+
yield(i.type)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Evaluate block given for the value of each token
|
51
|
+
# @see each
|
52
|
+
def each_value(&blck)
|
53
|
+
self._each do |i|
|
54
|
+
yield(i.value)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Evaluate block given for each token instance
|
59
|
+
# @see each
|
60
|
+
def each_token(&blck)
|
61
|
+
self._each do |i|
|
62
|
+
yield(i)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @endgroup
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
data/lib/ast_tokens.rb
ADDED
data/test/helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestTokeniser < Test::Unit::TestCase
|
4
|
+
context "When trying examples" do
|
5
|
+
should "run first" do
|
6
|
+
class Klass < Ast::Tokeniser
|
7
|
+
rule(:word, /[a-z]+/) {|i| i.reverse}
|
8
|
+
end
|
9
|
+
result = [[:word, "sdrawkcab"], [:word, "forwards"]]
|
10
|
+
assert_equal result, Klass.tokenise("backwards sdrawrof")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ast_ast
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 0.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Joshua Hawxwell
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-09-28 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: thoughtbot-shoulda
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: yard
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
description: Easily convert strings to Tokens and then on to an Abstract Syntax Tree easily. (Very far from finished!)
|
50
|
+
email: m@hawx.me
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files:
|
56
|
+
- LICENSE
|
57
|
+
- README.md
|
58
|
+
files:
|
59
|
+
- .document
|
60
|
+
- .gitignore
|
61
|
+
- LICENSE
|
62
|
+
- README.md
|
63
|
+
- Rakefile
|
64
|
+
- VERSION
|
65
|
+
- lib/ast_ast.rb
|
66
|
+
- lib/ast_ast/ast.rb
|
67
|
+
- lib/ast_ast/token.rb
|
68
|
+
- lib/ast_ast/tokeniser.rb
|
69
|
+
- lib/ast_ast/tokens.rb
|
70
|
+
- lib/ast_ast/tree.rb
|
71
|
+
- lib/ast_tokens.rb
|
72
|
+
- test/helper.rb
|
73
|
+
- test/test_ast_ast.rb
|
74
|
+
- test/test_tokeniser.rb
|
75
|
+
has_rdoc: true
|
76
|
+
homepage: http://github.com/hawx/ast_ast
|
77
|
+
licenses: []
|
78
|
+
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options:
|
81
|
+
- --charset=UTF-8
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: 3
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
hash: 3
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
requirements: []
|
103
|
+
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 1.3.7
|
106
|
+
signing_key:
|
107
|
+
specification_version: 3
|
108
|
+
summary: String -> Tokens -> AST
|
109
|
+
test_files:
|
110
|
+
- test/helper.rb
|
111
|
+
- test/test_ast_ast.rb
|
112
|
+
- test/test_tokeniser.rb
|