Module: LangScan::Scheme

Defined in:
ext/langscan/scheme/scheme/scheme.c,
lib/langscan/scheme.rb

Defined Under Namespace

Classes: Tokenizer

Constant Summary collapse

Keywords =
%w(
  else => define unquote unquote-splicing quote lambda if
  set! begin cond and or case let let* letrec do delay quasiquote
  syntax-rules define-syntax
)
KeywordsHash =
{}
NotFuncallWordsHash =
{"lambda" => "lambda"}
NotFuncall2ndOuterWords =
%w(
  let let* letrec let-syntax letrec-syntax do
)
NotFuncall2ndOuterWordsHash =
{}

Class Method Summary collapse

Class Method Details

.abbrevObject



32
33
34
# File 'lib/langscan/scheme.rb', line 32

def abbrev
  "scheme"
end

.extnamesObject



36
37
38
# File 'lib/langscan/scheme.rb', line 36

def extnames
  [".scm"]
end

.funcall_list?(list) ⇒ Boolean

Returns:

  • (Boolean)


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/langscan/scheme.rb', line 92

def funcall_list?(list)
  if list.before_open_length == 0
    return true
  end
  if NotFuncallWordsHash[list.around_open(-1).text]
    return false
  end
  if quote_list?(list)
    return false
  end
  outer = list.outer
  second_outer = outer.outer unless outer == nil
  if second_outer and NotFuncall2ndOuterWordsHash[second_outer.around_open(1).text]
    if NotFuncall2ndOuterWordsHash[outer.around_open(-1).text]
      return false
    end
  end
  return true
end

.fundef_list?(list) ⇒ Boolean

Returns:

  • (Boolean)


85
86
87
88
89
90
# File 'lib/langscan/scheme.rb', line 85

def fundef_list?(list)
  if list.before_open_length >= 1 && list.around_open(-1).text == "define"
    return true
  end
  return false
end

.nameObject



27
28
29
# File 'lib/langscan/scheme.rb', line 27

def name
  "Scheme"
end

.quote_list?(list) ⇒ Boolean

Returns:

  • (Boolean)


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/langscan/scheme.rb', line 116

def quote_list?(list)
  l = list
  nest = 0
  while l
    if l.before_open_length >= 1
      before = l.around_open(-1)
      if before.type == :quote_chars
        return true if before.text.include?("'")
        nest = nest + quote_nestlevel(before.text)
      end
    end
    if l.after_open_length >= 1
      after = l.around_open(1)
      if after.text == 'quote'
        return true
      elsif after.text == 'quasiquote'
        nest = nest + 1
      elsif after.text == 'unquote'
        nest = nest - 1
      end
    end
    l = l.outer
  end
  return nest > 0
end

.quote_nestlevel(str) ⇒ Object



112
113
114
# File 'lib/langscan/scheme.rb', line 112

def quote_nestlevel(str)
  str.count("`") - str.count(",")
end

.scan(input, &block) ⇒ Object

LangScan::Scheme.scan iterates over Scheme program. It yields for each Fragment.



42
43
44
45
# File 'lib/langscan/scheme.rb', line 42

def scan(input, &block)
  sorter = PairMatcher.fragmentsorter(block)
  scan_unsorted(input, &sorter)
end

.scan_unsorted(input, &block) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/langscan/scheme.rb', line 47

def scan_unsorted(input, &block)
  pm = LangScan::PairMatcher.new(2,2,2,2)
  pm.define_intertoken_fragment :space, nil
  pm.define_intertoken_fragment :comment, nil
  pm.define_pair :paren, :punct, "(", :punct, ")"
  pm.define_pair :vector, :punct, "#(", :punct, ")"
  reporter = lambda {|f|
    if (f.type == :ident || f.type == :funcall) && KeywordsHash[f.text]
      f.type = :keyword
    end
    if f.type == :number
      f.type = if f.text.include?("i")
                 :imaginary
               elsif f.text =~ /[.\/]|[0-9]#*[esfdl][0-9\-+]/
                 :floating
               else
                 :integer
               end
    end
    if f.type == :quote_chars
      f.type = :punct
    end
    yield f
  }
  pm.parse(LangScan::Scheme::Tokenizer.new(input), reporter) {|list|
    if list.around_open(1).type == :ident
      list.around_open(1).type = case
                                 when fundef_list?(list)
                                   :fundef
                                 when funcall_list?(list)
                                   :funcall
                                 else
                                   :ident
                                 end
    end
  }
end