Class: Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/schaefer/parser.rb

Instance Method Summary collapse

Instance Method Details

#convertLiterals(data) ⇒ Object



103
104
105
106
107
108
109
110
111
112
# File 'lib/schaefer/parser.rb', line 103

def convertLiterals(data)
  return recursiveMap(data) do |x|
    case x
    when nil then []
    when true then :"#t"
    when false then :"#f"
    else x
    end
  end
end

#convertTokens(tokens) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/schaefer/parser.rb', line 64

def convertTokens(tokens)
  convertedTokens = []
  tokens.each do |token|
    convertedTokens << "(" and next if token == "("
    convertedTokens << ")" and next if token == ")"
    convertedTokens << token.to_i and next if isInteger?(token)
    convertedTokens << token.to_sym and next if isSymbol?(token)
    convertedTokens << eval(token) and next if isString?(token)
    convertedTokens << token and next if isComma?(token)
    raise Exception, "Unrecognized token: #{token}"
  end
  return convertedTokens
end

#formStructure(tokens, offset = 0) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/schaefer/parser.rb', line 78

def formStructure(tokens, offset = 0)
  structure = []
  while offset < tokens.length do
    if tokens[offset] == "("
      offset, tempArray = formStructure(tokens, offset + 1)
      structure << tempArray
    elsif tokens[offset] == ")"
      break
    else
      structure << tokens[offset]
    end
    offset += 1
  end
  return [offset, structure]
end

#isComma?(string) ⇒ Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/schaefer/parser.rb', line 60

def isComma?(string)
  return isMatch?(string, /.*,.*/)
end

#isInteger?(string) ⇒ Boolean

return true if string is made of any number of numerals optionally preceded by a + or -

Returns:

  • (Boolean)


52
53
54
# File 'lib/schaefer/parser.rb', line 52

def isInteger?(string) #return true if string is made of any number of numerals optionally preceded by a + or -
  return isMatch?(string, /[\-\+]?[0-9]+/)
end

#isMatch?(string, pattern) ⇒ Boolean

check if type is a match, returns false if no, true if yes

Returns:

  • (Boolean)


42
43
44
45
46
# File 'lib/schaefer/parser.rb', line 42

def isMatch?(string, pattern) #check if type is a match, returns false if no, true if yes
  match = string.match(pattern)
  return false unless match
  match[0].length == string.length
end

#isString?(string) ⇒ Boolean

return true if string is text surrounded by quotes

Returns:

  • (Boolean)


56
57
58
# File 'lib/schaefer/parser.rb', line 56

def isString?(string) #return true if string is text surrounded by quotes
  return isMatch?(string, /"([^"\\]|\\.)*"/)
end

#isSymbol?(string) ⇒ Boolean

return true if string is anything other than parenthasees, quotes, or commas

Returns:

  • (Boolean)


48
49
50
# File 'lib/schaefer/parser.rb', line 48

def isSymbol?(string) #return true if string is anything other than parenthasees, quotes, or commas
  return isMatch?(string, /[^\"\'\,\(\)]+/)
end

#parse(string) ⇒ Object



94
95
96
97
98
99
100
101
# File 'lib/schaefer/parser.rb', line 94

def parse(string)
  string, literals = pullSLiterals(string)
  tokens = tokenize(string)
  tokens = replaceSLiterals(tokens, literals)
  tokens = convertTokens(tokens)
  structure = formStructure(tokens)[1]
  return structure
end

#pullSLiterals(string) ⇒ Object

method used to remove all string literals, save them in an array, and replace them with a set string that will not interfere with parsing



3
4
5
6
7
8
9
10
11
12
# File 'lib/schaefer/parser.rb', line 3

def pullSLiterals(string) #method used to remove all string literals, save them in an array, and replace them with a set string that will not interfere with parsing
  pattern = /"([^"\\]|\\.)*"/
  replace = "***STRING-LITERAL***"
  literals = []
  string.gsub(pattern) do |occurence|
    literals << occurence
  end
  string = string.gsub(pattern, replace)
  return [string, literals]
end

#replaceSLiterals(tokens, literals) ⇒ Object

method used to restore string literals in our tokens array now that we dont have to worry about special cases



32
33
34
35
36
37
38
39
40
# File 'lib/schaefer/parser.rb', line 32

def replaceSLiterals(tokens, literals) #method used to restore string literals in our tokens array now that we dont have to worry about special cases
  return tokens.map do |token|
    if token == "***STRING-LITERAL***"
      literals.shift
    else
      token
    end
  end
end

#tokenize(string) ⇒ Object

method used split program into tokens by adding spaces arround ‘(’s and calling string.split(‘ ’)



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/schaefer/parser.rb', line 14

def tokenize(string) #method used split program into tokens by adding spaces arround '('s and calling string.split(' ')
  numOpen = string.count("(")
  numClose = string.count(")")
  numMissing = 0
  if numOpen > numClose
    numMissing = numOpen - numClose
    raise RuntimeError, "#{numMissing} missing close parenthasees"
  elsif numClose > numOpen
    numMissing = numClose - numOpen
    raise RuntimeError, "#{numMissing} extra close parenthasees"
  elsif numClose == numOpen
    string = string.gsub("(", " ( ")
    string = string.gsub(")", " ) ")
    tokens = string.split(" ")
    return tokens
  end
end

#toToken(data) ⇒ Object

Convert a set of nested arrays back into an S-Expression



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/schaefer/parser.rb', line 115

def toToken(data)
  data = convertLiterals(data)
  if(data.is_a?(Array))
    mapped = data.map do |item|
      if(item.is_a?(Array))
        toToken(item)
      else
        item.to_s
      end
    end
    "(" + mapped.join(" ") + ")"
  elsif (data.is_a?(Hash))
    mapped = data.map do |key, value|
      key = toToken(key)
      value = toToken(value)
      key + "=>" + value
    end
    "(" + mapped.join(" ") + ")"
  else
    data.to_s
  end
end