1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # This file is free software, which comes along with NIT. This software is
4 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
5 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
6 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
7 # is kept unaltered, and a notification of the changes is added.
8 # You are allowed to redistribute it and sell it, alone or is a part of
11 # S-Expression parsing facilities
14 intrude import parser_base
16 # Any S-Expression entity
17 abstract class SExpEntity
19 # Location in the source document
20 var location
: nullable Location
23 # A full S-Expression, delimited by `(` and `)`
28 var content
= new Array[SExpEntity]
30 redef fun to_s
do return "({content.join(" ")})"
32 # Returns a pretty-printable version of self
34 # assert "( ( sp 12.3 ) \"DQString\")".to_sexp.as(SExp).pretty_to_s == "(\n\t(\n\t\tsp\n\t\t12.30\n\t)\n\t\"DQString\"\n)"
35 fun pretty_to_s
: String do return recurse_to_s
(0)
37 private fun recurse_to_s
(depth
: Int): String do
38 var s
= "{"\t" * depth}(\n"
41 s
+= i
.recurse_to_s
(depth
+ 1)
45 s
+= "\t" * (depth
+ 1)
49 return s
+ "{"\t" * depth})"
53 # A Double-quoted String
57 # Double-quoted string
60 redef fun to_s
do return content
67 # Floating-point value
70 redef fun to_s
do return content
.to_precision
(2)
73 # Any Identifier, non string and non-float
77 # S-Exp compatible identifier
80 redef fun to_s
do return content
83 # An error parsing S-Expressions
90 redef fun to_s
do return "S-Expression error: {message} at {location or else "unknown location"}"
93 # S-Expression processor
97 # Parses an S-Expression entity
98 fun parse_entity
: SExpEntity do
99 var srclen
= src
.length
100 var delims
= once
['(', ')', '"']
102 if pos
>= srclen
then return new SExpError(new Location(line
, line_offset
), "Empty S-Expression")
106 var loc
= new Location(line
, line_offset
)
108 while pos
< srclen
and src
[pos
] != ')' do
110 if p
isa SExpError then break
114 if pos
< srclen
and src
[pos
] == ')' then
118 return new SExpError(loc
, "Incomplete S-Expression")
120 else if c
== '"' then
122 var loc
= new Location(line
, line_offset
)
127 return new SExpDQString(loc, src.substring(stdq, endq - stdq))
130 var loc = new Location(line, line_offset)
131 while pos < srclen and not c.is_whitespace and not delims.has(c) do
135 if delims.has(c) or c.is_whitespace then pos -= 1
136 if pos >= srclen then return new SExpError(loc, "Invalid S-Expression
")
138 var cntstr = src.substring(stid, endid - stid)
140 if cntstr.is_numeric then
141 cnt = new SExpFloat(loc, cntstr.to_f)
143 cnt = new SExpId(loc, cntstr)
152 # Tries to parse `self` as an S-Expression
153 fun to_sexp: SExpEntity do return (new SExpProcessor(self.to_s)).parse_entity