S-expressions: Difference between revisions
m
→JS Functional
m (→JS Functional) |
|||
(12 intermediate revisions by 9 users not shown) | |||
Line 21:
The reader should be able to read the following input
<
(data (!@# (4.5) "(more" "data)")))</
and turn it into a native datastructure. (see the [[#Pike|Pike]], [[#Python|Python]] and [[#Ruby|Ruby]] implementations for examples of native data structures.)
Line 32:
Let the writer produce pretty printed output with indenting and line-breaks.
<br><br>
=={{header|11l}}==
{{trans|Nim}}
<syntaxhighlight lang="11l">T Token
T.enum Kind
INT
FLOAT
STRING
IDENT
LPAR
RPAR
END
Kind kind
String val
F (kind, val = ‘’)
.kind = kind
.val = val
F lex(input_str)
[Token] result
V pos = 0
F current()
R I @pos < @input_str.len {@input_str[@pos]} E Char("\0")
L pos < input_str.len
V ch = input_str[pos]
I ch == ‘(’
pos++
result.append(Token(Token.Kind.LPAR))
E I ch == ‘)’
pos++
result.append(Token(Token.Kind.RPAR))
E I ch C ‘0’..‘9’
V num = ‘’
V kind = Token.Kind.INT
L current() C ‘0’..‘9’
num ‘’= current()
pos++
I current() == ‘.’
num ‘’= current()
kind = FLOAT
pos++
L current() C ‘0’..‘9’
num ‘’= current()
pos++
result.append(Token(kind, num))
E I ch C (‘ ’, "\t", "\n", "\r")
pos++
E I ch == ‘"’
V str = ‘’
pos++
L current() != ‘"’
str ‘’= current()
pos++
pos++
result.append(Token(Token.Kind.STRING, str))
E
V BannedChars = Set([‘ ’, "\t", ‘"’, ‘(’, ‘)’, ‘;’])
V ident = ‘’
L current() !C BannedChars
ident ‘’= current()
pos++
result.append(Token(Token.Kind.IDENT, ident))
result.append(Token(Token.Kind.END))
R result
F indent(s, count)
R (count * ‘ ’)‘’s.replace("\n", "\n"(count * ‘ ’))
T SExpr
T.enum Kind
INT
FLOAT
STRING
IDENT
LIST
Kind kind
String val
[SExpr] children
F (kind, val = ‘’)
.kind = kind
.val = val
F to_str()
I .kind C (SExpr.Kind.INT, SExpr.Kind.FLOAT, SExpr.Kind.IDENT)
R .val
E I .kind == STRING
R ‘"’(.val)‘"’
E I .kind == LIST
V result = ‘(’
L(i, ex) enumerate(.children)
I ex.kind == LIST & ex.children.len > 1
result ‘’= "\n"
result ‘’= indent(ex.to_str(), 2)
E
I i > 0
result ‘’= ‘ ’
result ‘’= ex.to_str()
R result‘)’
assert(0B)
V input_str = ‘
((data "quoted data" 123 4.5)
(data (!@# (4.5) "(more" "data)")))
’
V tokens = lex(input_str)
V pos = 0
F current()
R I :pos < :tokens.len {:tokens[:pos]} E Token(Token.Kind.END)
F parse() -> SExpr
V token = current()
:pos++
I token.kind == INT
R SExpr(SExpr.Kind.INT, token.val)
E I token.kind == FLOAT
R SExpr(SExpr.Kind.FLOAT, token.val)
E I token.kind == STRING
R SExpr(SExpr.Kind.STRING, token.val)
E I token.kind == IDENT
R SExpr(SExpr.Kind.IDENT, token.val)
E I token.kind == LPAR
V result = SExpr(SExpr.Kind.LIST)
L current().kind !C (Token.Kind.RPAR, Token.Kind.END)
result.children.append(parse())
assert(current().kind != END, ‘Missing right paren ')'’)
:pos++
R result
assert(0B)
print(parse().to_str())</syntaxhighlight>
{{out}}
<pre>
(
(data "quoted data" 123 4.5)
(data
(!@# (4.5) "(more" "data)")))
</pre>
=={{header|Ada}}==
Line 39 ⟶ 186:
Specification of package S_Expr:
<
private with Ada.Containers.Indefinite_Vectors;
Line 93 ⟶ 240:
end record;
end S_Expr;</
The implementation of S_Expr:
<
package body S_Expr is
Line 151 ⟶ 298:
end Print;
end S_Expr;</
Specification and Implementation of S_Expr.Parser (a child package of S_Expr):
<
package S_Expr.Parser is
Line 161 ⟶ 308:
-- the result of a parse process is always a list of expressions
end S_Expr.Parser;</
<
package body S_Expr.Parser is
Line 272 ⟶ 419:
end Parse;
end S_Expr.Parser;</
The main program Test_S_Expr:
<
procedure Test_S_Expr is
Line 298 ⟶ 445:
Expression_List.First.Print(Indention => 0);
-- Parse will output a list of S-Expressions. We need the first Expression.
end Test_S_Expr;</
{{out}}
Line 326 ⟶ 473:
=={{header|ALGOL 68}}==
<
CHAR nl = REPR 10;
# mode representing an S-expression #
Line 452 ⟶ 599:
+ nl
)
)</
{{out}}
<pre>
Line 559 ⟶ 706:
<
wspace←' ',⎕TC ⍝ whitespace is space, tab, cr, lf
Line 622 ⟶ 769:
}
</syntaxhighlight>
=={{header|Arturo}}==
<
((data "quoted data" 123 4.5)
(data (!@# (4.5) "(more" "data)")))
Line 632 ⟶ 779:
s: first to :block code
inspect.muted s
print as.code s</
{{out}}
Line 660 ⟶ 807:
=={{header|AutoHotkey}}==
<
Str := RegExReplace(Str, "s)(?<![\\])"".*?[^\\]""(*SKIP)(*F)|((?<![\\])[)(]|\s)", "`n$0`n")
Str := RegExReplace(Str, "`am)^\s*\v+") , Cnt := 0
Line 675 ⟶ 822:
Res .= "`t"
return Res
}</
Examples:<
(
((data da\(\)ta "quot\\ed data" 123 4.5)
("data" (!@# (4.5) "(mo\"re" "data)")))
)
MsgBox, 262144, , % S_Expressions(Str)</
{{out}}
<pre>(
Line 707 ⟶ 854:
=={{header|C}}==
<
#include <stdlib.h>
#include <ctype.h>
Line 932 ⟶ 1,079:
print_expr(x, 0);
return 0;
}</
{{out}}<syntaxhighlight lang="text">input is:
((data da\(\)ta "quot\\ed data" 123 4.5)
("data" (!@# (4.5) "(mo\"re" "data)")))
Line 956 ⟶ 1,103:
)
)
)</
=={{header|C sharp|C#}}==
Line 963 ⟶ 1,110:
Git repository with code and tests can be found here: https://github.com/ichensky/SExpression/tree/rosettacode
<
using System;
using System.Collections.Generic;
Line 1,010 ⟶ 1,157:
}
</syntaxhighlight>
<
using System;
using System.Collections.Generic;
Line 1,196 ⟶ 1,343:
}
}
</syntaxhighlight>
<
using System;
using System.Collections.Generic;
Line 1,218 ⟶ 1,365:
}
}
</syntaxhighlight>
{{out}}
<pre>
Line 1,231 ⟶ 1,378:
apart from writing it out, which fulfils this task's requirements. With some more work
this code might actually be useful.
<
#include <iomanip>
#include <iostream>
Line 1,501 ⟶ 1,648:
}
return 0;
}</
{{out}}
Line 1,527 ⟶ 1,674:
=={{header|Ceylon}}==
<
shared String symbol;
string => symbol;
Line 1,695 ⟶ 1,842:
prettyPrint(tree);
}
</syntaxhighlight>
{{out}}
<pre>
Line 1,721 ⟶ 1,868:
=={{header|CoffeeScript}}==
{{improve|CoffeeScript|This solution does not reproduce unquoted strings as per task description}}
<
# This code works with Lisp-like s-expressions.
#
Line 1,852 ⟶ 1,999:
console.log "output:\n#{pp output}\n"
console.log "round trip:\n#{sexp output}\n"
</syntaxhighlight>
{{out}}
<syntaxhighlight lang="text">
> coffee sexp.coffee
input:
Line 1,884 ⟶ 2,031:
round trip:
(("data" "quoted data with escaped \"" 123 4.5 "14") ("data" ("!@#" (4.5) "(more" "data)")))
</syntaxhighlight>
=={{header|Common Lisp}}==
Line 1,902 ⟶ 2,049:
Unfortunately, our pointy-haired boss has asked you to write a parser for an unusual s-expression syntax that uses square brackets instead of parenthesis. In most programming languages, this would necessitate writing an entire parser. Fortunately, the Common Lisp reader can be modified through the use of macro-characters to accomplish this task. When the reader parses a macro-character token, a function associated with the macro-character is called. As evidenced below, modifying the behavior of the Lisp reader by setting macro-character functions to handle additional sytax requires far less work than writing a complete parser from scratch.
<
(declare (ignore char))
(read-delimited-list #\] stream t))
(set-macro-character #\[ #'lsquare-reader) ;;Call the lsquare-reader function when a '[' token is parsed
(set-macro-character #\] (get-macro-character #\) nil)) ;;Do the same thing as ')' when a ']' token is parsed</
Unit test code:
<
;;test string and the cdr (right side) the expected result of reading the S-Exp.
(setf unit-tests
Line 1,923 ⟶ 2,070:
(dolist (test unit-tests)
(format t "String: ~23s Expected: ~23s Actual: ~s~%"
(car test) (cdr test) (read-from-string (car test)))))</
{{out| Unit test output}}
<pre>CL-USER> (run-tests)
Line 1,957 ⟶ 2,104:
===Writing S-Expressions===
The next step in this task is to write a standard Lisp s-expression in the square bracket notation.
<
"Writes a Lisp s-expression in square bracket notation."
(labels ((parse (sexp)
Line 1,980 ⟶ 2,127:
(subseq str 0 last-char)
str)))))))
(concatenate 'string "[" (fix-spacing (parse sexp)) "]")))</
Unit test code:
<
(1 (2 (3 (4)))) ((1) (2) (3)) ()))
Line 1,988 ⟶ 2,135:
(dolist (test unit-tests)
(format t "Before: ~18s After: ~s~%"
test (write-sexp test))))</
{{out|Unit test output}}
<pre>CL-USER> (run-tests)
Line 2,014 ⟶ 2,161:
a native floating point type, floating point numbers are not.
<
include "strings.coh";
include "malloc.coh";
Line 2,279 ⟶ 2,426:
print("Parsed:\n");
prettyprint(ParseSExp(str));
print_nl();</
{{out}}
Line 2,308 ⟶ 2,455:
=={{header|D}}==
<
std.functional, std.string;
Line 2,394 ⟶ 2,541:
"Printed: ".write;
pTest.writeSexp;
}</
{{out}}
<pre>Parsed: [[data, quoted data, 123, 4.5], [data, [!@#, [4.5], (more, data)]]]
Line 2,401 ⟶ 2,548:
=={{header|EchoLisp}}==
The '''(read-from-string input-string)''' function parses a string into an s-expression, which is the native representation of program/data in EchoLisp and the majority of Lisps .
<
(define input-string #'((data "quoted data" 123 4.5)\n(data (!@# (4.5) "(more" "data)")))'#)
Line 2,418 ⟶ 2,565:
(first(rest s-expr))
→ (data (!@# (4.5) "(more" "data)"))
</syntaxhighlight>
=={{header|F_Sharp|F#}}==
Implementation of S-expression parser in F# 4.7 language.
Line 2,431 ⟶ 2,578:
The file <code>SExpr.fs</code> containing the implementation:
<
module SExpr
(* This module is a very simple port of the OCaml version to F# (F-Sharp) *)
Line 2,663 ⟶ 2,810:
(* print_endline (string_of_sexpr_indent s) *)
printfn "%s" (string_of_sexpr_indent s)
</syntaxhighlight>
Line 2,670 ⟶ 2,817:
Read the experession from a file of preset it in the code.
<
module Program
(* Learn more about F# at https://fsharp.org *)
Line 2,708 ⟶ 2,855:
(* return an integer exit code *)
0
</syntaxhighlight>
{{out}}
Line 2,734 ⟶ 2,881:
Factor has a comprehensive prettyprinter which can print any Factor object in a readable way. Not only can we leverage it to easily print our native data structure, but we can also call <code>unparse</code> to convert it to a string. This leaves us with a string reminiscent of the original input, and we are able to take it the rest of the way with two simple regular expressions.
<
regexp sequences prettyprint words ;
IN: rosetta-code.s-expressions
Line 2,760 ⟶ 2,907:
sexp>seq dup seq>sexp
"Native:\n%u\n\nRound trip:\n%s\n" printf
] bi</
{{out}}
<pre>
Line 2,779 ⟶ 2,926:
=={{header|Go}}==
<
import (
Line 2,952 ⟶ 3,099:
fmt.Println(s.i)
}
}</
{{out}}
<pre>
Line 2,980 ⟶ 3,127:
=={{header|Haskell}}==
<
import qualified Text.Parsec.Prim as Prim
import Text.Parsec
Line 3,019 ⟶ 3,166:
"((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))"
putStrLn ("The input:\n" ++ expr ++ "\n\nParsed as:")
p expr</
{{Out}}
<pre>The input:
Line 3,030 ⟶ 3,177:
Or, parsing by hand (rather than with a parser combinator library) and printing a parse tree diagram:
<
import Data.Bifunctor (bimap)
import Data.List (mapAccumL)
Line 3,037 ⟶ 3,184:
import Data.Maybe (catMaybes, fromMaybe, listToMaybe)
import Data.Tree (Forest, Tree (..), drawForest)
------------------------ DATA TYPE -----------------------
data Val
Line 3,046 ⟶ 3,193:
| List [Val]
deriving (Eq, Show, Read)
instance Semigroup Val where
List a <> List b = List (a <> b)
instance Monoid Val where
mempty = List []
--------------------------- MAIN -------------------------
main :: IO ()
Line 3,062 ⟶ 3,209:
]
parse = fst (parseExpr (tokenized expr))
putStrLn $ treeDiagram $ forestFromVal parse
putStrLn "Serialized from the parse tree:\n"
putStrLn $ litVal parse
------------------- S-EXPRESSION PARSER ------------------
parseExpr :: [String] -> (Val, [String])
parseExpr = until finished parseToken . (mempty,)
finished :: (Val, [String]) -> Bool
finished (_, []) = True
finished (_, token : _) = ")" == token
parseToken :: (Val, [String]) -> (Val, [String])
parseToken (v, "(" : rest) =
Line 3,084 ⟶ 3,231:
parseToken (v, ")" : rest) = (v, rest)
parseToken (v, t : rest) = (v <> List [atom t], rest)
----------------------- TOKEN PARSER ---------------------
atom :: String -> Val
atom [] = mempty
Line 3,095 ⟶ 3,242:
catMaybes $
maybeRead . (<> (' ' : s)) <$> ["Int", "Float"]
maybeRead :: String -> Maybe Val
maybeRead = fmap fst . listToMaybe . reads
----------------------- TOKENIZATION ---------------------
tokenized :: String -> [String]
tokenized s = quoteTokens '"' s >>= go
Line 3,107 ⟶ 3,254:
go token@('"' : _) = [token]
go s = words $ spacedBrackets s
quoteTokens :: Char -> String -> [String]
quoteTokens q s = snd $ mapAccumL go False (splitOn [q] s)
Line 3,114 ⟶ 3,261:
| b = (False, '"' : s <> "\"")
| otherwise = (True, s)
spacedBrackets :: String -> String
spacedBrackets [] = []
Line 3,120 ⟶ 3,267:
| c `elem` "()" = ' ' : c : " " <> spacedBrackets cs
| otherwise = c : spacedBrackets cs
-------------------------
treeDiagram :: Forest Val -> String
treeDiagram = drawForest . fmap (fmap show)
forestFromVal :: Val -> Forest Val
forestFromVal (List xs) = treeFromVal <$> xs
treeFromVal :: Val -> Tree Val
treeFromVal (List xs) =
Node (Symbol "List") (treeFromVal <$> xs)
treeFromVal v = Node v []
litVal (Symbol x) = x
litVal (Int x) = show x
Line 3,142 ⟶ 3,289:
litVal (List [List xs]) = litVal (List xs)
litVal (List xs) = '(' : (unwords (litVal <$> xs) <> ")")
------------------------- GENERIC ------------------------
headDef :: a -> [a] -> a
headDef d [] = d
headDef _ (x : _) = x</
{{Out}}
<pre>Symbol "List"
Line 3,188 ⟶ 3,335:
The example takes single and double quotes. <br>
Single quotes were used instead of doubles in the input.
<
procedure main()
Line 3,247 ⟶ 3,394:
}
return T
end</
{{libheader|Icon Programming Library}}
Line 3,278 ⟶ 3,425:
This implementation does not support escape characters. If escape characters were added, we would need additional support in the tokenizer (an extra character class, and in the state table an extra column and two extra rows, or almost double the number of state transitions: 35 instead of 20), and additional support in the data language (unfmt would need to strip out escape characters and fmt would need to insert escape characters -- so each of these routines would also perhaps double in size.) And that's a lot of bulk for serialize/deserialize mechanism which, by design, cannot represent frequently used data elements (such as matrices and gerunds).
<
chrMap=: '()';'"';' ',LF,TAB,CR
Line 3,329 ⟶ 3,476:
readSexpr=: fmt L:0 @rdSexpr :.writeSexpr
writeSexpr=: wrSexpr @(unfmt L:0) :.readSexpr</
Example use:
<
┌───────────────────────────┬────────────────────────────────┐
│┌─────┬───────────┬───┬───┐│┌─────┬────────────────────────┐│
Line 3,345 ⟶ 3,492:
└───────────────────────────┴────────────────────────────────┘
writeSexpr readSexpr '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))'
((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))</
=={{header|Java}}==
Line 3,355 ⟶ 3,502:
====LispTokenizer.java====
<
import java.io.BufferedReader;
Line 3,465 ⟶ 3,612:
{
}
}</
====Token.java====
<
import java.io.StreamTokenizer;
Line 3,496 ⟶ 3,643:
}
}
}</
====Atom.java====
<
import jfkbits.LispParser.Expr;
Line 3,515 ⟶ 3,662:
}
}</
====StringAtom.java====
<
public class StringAtom extends Atom
Line 3,538 ⟶ 3,685:
}
}
</syntaxhighlight>
====ExprList.java====
<
import java.util.AbstractCollection;
Line 3,611 ⟶ 3,758:
}
}</
====LispParser.java====
<
Line 3,661 ⟶ 3,808:
}
</syntaxhighlight>
====LispParserDemo.java====
<
import jfkbits.LispParser;
import jfkbits.LispParser.ParseException;
Line 3,689 ⟶ 3,836:
}
}
}</
=={{header|JavaScript}}==
(for a '''bug-fix''' concerning \" and \n in strings see the [[Talk:S-expressions#JavaScript_version_bugfix_for_%5C%22_and_%5Cn_in_strings|Discussion]])
===Procedural===
<
var t = this.match(/\s*("[^"]*"|\(|\)|"|[^\s()"]+)/g)
for (var o, c=0, i=t.length-1; i>=0; i--) {
Line 3,730 ⟶ 3,878:
document.write('Invalid s-expr!', '<br>')
else
document.write('s-expr:<br>', sexpr, '<br><br>', sexpr.constructor != Array ? '' : 'pretty print:<br>' + sexpr.toPretty())</
{{out}}
<pre>text:
Line 3,762 ⟶ 3,910:
===Functional===
Showing the parse tree in
<
"use strict";
Line 3,771 ⟶ 3,919:
"((data \"quoted data\" 123 4.5)",
" (data (!@# (4.5) \"(more\" \"data)\")))"
]
.join("\n");
const [parse, residue] = parseExpr(
Line 3,777 ⟶ 3,926:
);
return 0 < residue.length
? `Unparsed tokens: ${JSON.stringify(residue)}`
parse.map(serialized).join(" ")
]
.join("\n\n")
: "Could not be parsed";
};
Line 3,812 ⟶ 3,964:
// An open bracket introduces recursion over
// a sub-expression to define a sub-list.
return "(" === token
const [expr, rest] = parseExpr(ts);
return [xs.concat([expr]), rest.slice(1)];
: [xs.concat(atom(token)), ts];
};
Line 3,825 ⟶ 3,979:
// atom :: String -> Expr
const atom = s =>
0 < s.length
? isNaN(s)
? "\"'".includes(s[0])
? s.slice(1, -1)
:
Line 3,842 ⟶ 3,994:
// Brackets and quoted or unquoted atomic strings.
quoteTokens("\"")(s).flatMap(
segment => "\"" !== segment[0]
? segment.replace(/([()])/gu, " $1 ")
.split(/\s+/u)
.filter(Boolean)
);
Line 3,854 ⟶ 4,006:
// Alternating unquoted and quoted segments.
s => s.split(q).flatMap(
(k, i) => even(i)
? [k]
);
Line 3,867 ⟶ 4,019:
const t = typeof e;
return "number" === t
? `${e}`
? `"${e}"`
? Array.isArray(e)
? `(${e.map(serialized).join(" ")})`
};
Line 3,894 ⟶ 4,046:
f => {
const go = x =>
p(x)
? x
: go(f(x));
return go;
Line 3,900 ⟶ 4,054:
return main();
})();</
{{Out}}
<pre>[
Line 3,933 ⟶ 4,087:
((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))</pre>
=={{header|jq}}==
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq'''
[[Category:PEG]]
This entry is based on a Parsing Expression Grammar (PEG) for S-expressions.
The idea is to pass a JSON object `{remainder:_, result:_ }` through a
jq pipeline corresponding to a PEG for S-expressions, consuming the
text in `.remainder` and building up `.result`.
For further details about this approach, see e.g.
[https://github.com/stedolan/jq/wiki/Parsing-Expression-Grammars jq as a PEG Engine].
<syntaxhighlight lang=jq>
# PEG infrastructure
def star(E): ((E | star(E)) // .) ;
### Helper functions:
# Consume a regular expression rooted at the start of .remainder, or emit empty;
# on success, update .remainder and set .match but do NOT update .result
def consume($re):
# on failure, match yields empty
(.remainder | match("^" + $re)) as $match
| .remainder |= .[$match.length :]
| .match = $match.string;
def parse($re):
consume($re)
| .result = .result + [.match] ;
def parseNumber($re):
consume($re)
| .result = .result + [.match|tonumber] ;
def eos: select(.remainder == "");
# whitespace
def ws: consume("[ \t\r\n]*");
def box(E):
((.result = null) | E) as $e
| .remainder = $e.remainder
| .result += [$e.result] # the magic sauce
;
# S-expressions
# Input: a string
# Output: an array representation of the input if it is an S-expression
def SExpression:
def string: consume("\"") | parse("[^\"]") | consume("\"");
def identifier: parse("[^ \t\n\r()]+");
def decimal: parseNumber("[0-9]+([.][0-9]*)?");
def hex: parse("0x[0-9A-Fa-f]+") ;
def number: hex // decimal;
def atom: ws | (string // number // identifier);
def SExpr: ws | consume("[(]") | ws | box(star(atom // SExpr)) | consume("[)]");
{remainder: .} | SExpr | ws | eos | .result;
SExpression
</syntaxhighlight>
'''Invocation:'''
<pre>
cat << EOF |
((data "quoted data" 123 4.5)
(data (!@# (4.5) "(more" "data)")))
EOF
jq -Rsc -f s-expression.jq
</pre>
{{output}}
<pre>
[[["data","\"quoted","data\"",123,4.5],["data",["!@#",[4.5],"\"",["more\"","\"data"],"\""]]]]
</pre>
=={{header|Julia}}==
<
function rewritequotedparen(s)
segments = split(s, "\"")
Line 4,010 ⟶ 4,237:
println("The processed native structure is:\n", nat)
println("The reconstructed string is:\n"), printAny(nat)
</syntaxhighlight>
{{output}}<pre>
The input string is:
Line 4,026 ⟶ 4,253:
=={{header|Kotlin}}==
{{trans|JavaScript}}
<
const val INDENT = 2
Line 4,123 ⟶ 4,350:
tokens2.prettyPrint()
}
}</
{{out}}
Line 4,181 ⟶ 4,408:
Tested with Lua 5.3.5 and LPeg 1.0.2-1.
<
imports = 'P R S C V match'
Line 4,207 ⟶ 4,434:
'S';
S = ws * lpar * C((atom + V'S')^0) * rpar / tolist
}</
Now to use the <i>sexpr</i> pattern:
<
((data "quoted data" 123 4.5)
(data (!@# (4.5) "(more" "data)")))
Line 4,235 ⟶ 4,462:
check(eg_produced, eg_expected)
print("checks out!") -- won't get here if any <i>check()</i> assertion fails
</syntaxhighlight>
And here's the pretty printer, whose output looks like all the others:
<
local function prindent(fmt, expr)
io.write(indent) -- no line break
Line 4,264 ⟶ 4,491:
end
pprint(eg_expected, '')</
=={{header|Nim}}==
<
const Input = """
Line 4,412 ⟶ 4,639:
else: nil
echo parse()</
{{out}}
Line 4,424 ⟶ 4,651:
=={{header|OCaml}}==
You may be interested in this [https://dev.realworldocaml.org/data-serialization.html chapter of the book Real World OCaml].
The file <code>SExpr.mli</code> containing the interface:
<
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *)
Line 4,457 ⟶ 4,683:
val string_of_sexpr_indent : sexpr list -> string
(** same than [string_of_sexpr] but with indentation *)</
The file <code>SExpr.ml</code> containing the implementation:
<
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *)
(* modified to match the task description *)
Line 4,638 ⟶ 4,864:
let print_sexpr_indent s =
print_endline (string_of_sexpr_indent s)</
Then we compile this small module and test it in the interactive loop:
Line 4,676 ⟶ 4,902:
=={{header|Perl}}==
<
use strict;
use warnings;
Line 4,730 ⟶ 4,956:
ref($_) eq 'ARRAY' ? sexpr2txt($_) : $$_
} @{$_[0]} ]})}
}</
Check:
<
((data "quoted data" 123 4.5)
Line 4,744 ⟶ 4,970:
# Convert back
print sexpr2txt($s)."\n";</
Output:
<pre>$VAR1 = [
Line 4,773 ⟶ 4,999:
that may not be clear on the display: 4e-5 and 4-e5 may appear similar but the latter is probably a parse failure. It may
be more sensible for get_term() to raise an error if the scanf fails, than assume it is a symbol like it does now.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">s_expr_str</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
((data "quoted data" 123 4.5)
(data (!@# (4.5) "(more" "data)")))"""</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">skip_spaces</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">sidx</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">sidx</span><span style="color: #0000FF;"><=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">],{</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\t'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\r'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">do</span> <span style="color: #000000;">sidx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">sidx</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">get_term</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">sidx</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- get a single quoted string, symbol, or number.</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'\"'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">ch</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">sidx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">ch</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'\\'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">sidx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">ch</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'\"'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">sidx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">else</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">asnumber</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'9'</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">')'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\t'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\r'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">ch</span>
<span style="color: #000000;">sidx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">sidx</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">asnumber</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">scanres</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%f"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">scanres</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">scanres</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- error? (failed to parse number)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">parse_s_expr</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">sidx</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">element</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">'('</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">sidx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">sidx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">skip_spaces</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- error? (if past end of string/missing ')')</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">')'</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'('</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">element</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">parse_s_expr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">element</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">get_term</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">element</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">sidx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">skip_spaces</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s_expr</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">sidx</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">s_expr</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">parse_s_expr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s_expr_str</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">sidx</span><span style="color: #0000FF;"><=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s_expr_str</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"incomplete parse(\"%s\")\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">s_expr_str</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">..$]})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\nThe string:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">s_expr_str</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\nDefault pretty printing:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--?s_expr</span>
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s_expr</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\nBespoke pretty printing:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--ppEx(s_expr,{pp_Nest,1,pp_StrFmt,-1,pp_IntCh,false,pp_Brkt,"()"})</span>
<span style="color: #7060A8;">ppEx</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s_expr</span><span style="color: #0000FF;">,{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_StrFmt</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_IntCh</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_Brkt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"()"</span><span style="color: #0000FF;">})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 4,880 ⟶ 5,109:
=={{header|PicoLisp}}==
The '[http://software-lab.de/doc/refA.html#any any]' function parses an s-expression from a string (indentical to the way '[http://software-lab.de/doc/refR.html#read read]' does this from an input stream).
<
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))
Line 4,900 ⟶ 5,129:
+-- "(more"
|
+-- "data)"</
Implementing a subset of 'any' explicitly:
<
(case (skip)
("(" (char) (readList))
Line 4,927 ⟶ 5,156:
(until (or (sp? (peek)) (member (peek) '("(" ")")))
(link (char)) ) )
(or (format X) (intern (pack X))) ) )</
It can be used in a pipe to read from a string:
<
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</
'[http://software-lab.de/doc/refS.html#sym sym]' does the reverse (i.e. builds a symbol (string) from an expression).
<
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</
Implementing a subset of the built-in printer:
<
(cond
((pair Expr)
Line 4,948 ⟶ 5,177:
(mapc Fun (chop Expr))
(Fun "\"") )
(T (mapc Fun (chop Expr))) ) )</
This can be used for plain printing
<
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))
prin )
((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</
or to collect the characters into a string:
<
(make
(printSexpr
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))
link ) ) )
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</
=={{header|Pike}}==
<
{
string _sprintf(int type)
Line 5,068 ⟶ 5,297:
string input = "((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))";
array data = group(tokenizer(input))[0];
string output = sexp(data);</
Output:
Line 5,080 ⟶ 5,309:
=={{header|Potion}}==
How values are stored: Tuples for list, integers for integers, floats for floats, strings for symbols, quoted strings for strings. This implementation is not the most elegant/succinct or practical (it's trusty and has no real error handling).
<
iswhitespace = (c): c ord == 10 or c ord == 13 or c == " ".
Line 5,151 ⟶ 5,380:
parsesexpr("((data \"quoted data\" 123 4.5)
(data (!@# (4.5) \"(more\" \"data)\")))") string print
"\n" print</
=={{header|Python}}==
===Procedural===
<
dbg = False
Line 5,214 ⟶ 5,443:
print("\nParsed to Python:", parsed)
print("\nThen back to: '%s'" % print_sexp(parsed))</
;Output:
Line 5,225 ⟶ 5,454:
;Simpler parser:
Note that in the example above the parser also recognises and changes the type of some tokens as well as generating a nested list. If that functionality is not needed, or better done elsewhere, then the parse function can be achieved more simply by just applying the regexp:
<
>>> x = [[(t,v) for t,v in termtypes.groupdict().items() if v][0] for termtypes in re.finditer(term_regex, sexp)]
>>> pp(x)
Line 5,247 ⟶ 5,476:
('brackr', ')'),
('brackr', ')')]
>>> </
===Functional===
Composing functionally, and writing out a tree diagram, and a serialization, of the parse.
<
from itertools import chain, repeat
Line 5,498 ⟶ 5,727:
# MAIN ---
if __name__ == '__main__':
main()</
{{Out}}
<pre>{'name': 'List'}
Line 5,535 ⟶ 5,764:
Racket has builtin support for S-expressions in the form of the read function.
<
#lang racket
(define input
Line 5,545 ⟶ 5,774:
(read (open-input-string input))
</syntaxhighlight>
Output:
<pre>
Line 5,557 ⟶ 5,786:
This parses the task, but it isn't really a good lisp parser, because it always wants whitespace between lists, so <code>(()())</code> will fail ( <code>(() ())</code> wont)
<syntaxhighlight lang="raku"
rule TOP {^ <s-list> $};
Line 5,599 ⟶ 5,828:
say "the expression:\n$s-exp\n";
say "the Raku expression:\n{$raku_array.raku}\n";
say "and back:\n{s-exp_writer($raku_array)}";</
{{out}}
Line 5,619 ⟶ 5,848:
It would normally be considered improper, but the literal string delimiters were left intact; making it much easier to understand what is/was being parsed.
<
input= '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))'
say center('input', length(input), "═") /*display the header title to terminal.*/
Line 5,674 ⟶ 5,903:
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
add!: if !='' then return; #=#+1; @.#=left("", max(0, tabs*(level-1)))!; !=; return</
{{out|output|text= when using the default input:}}
<pre>
Line 5,703 ⟶ 5,932:
=={{header|Ruby}}==
{{works with|Ruby|1.9}}
<
def initialize(str)
@original = str
Line 5,824 ⟶ 6,053:
puts "original sexpr:\n#{sexpr.original}"
puts "\nruby data structure:\n#{sexpr.data}"
puts "\nand back to S-Expr:\n#{sexpr.to_sexpr}"</
{{out}}
Line 5,841 ⟶ 6,070:
=={{header|Rust}}==
lib.rs:
<
//! This implementation isn't based on anything in particular, although it's probably informed by a
//! lot of Rust's JSON encoding code. It should be very fast (both encoding and decoding the toy
Line 6,232 ⟶ 6,461:
println!("{:?}", SExp::parse(ctx));
}
</
<pre>
Ok("((\"data\" \"quoted data\" 123 4.5) (\"data\" (\"!@#\" (4.5) \"(more\" \"data)\")))")
Line 6,249 ⟶ 6,478:
Using guile scheme 2.0.11
<
(define (help port)
(let ((char (read-char port)))
Line 6,292 ⟶ 6,521:
(format-sexpr (sexpr-read
(open-input-string "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))")))</
Output:
Line 6,317 ⟶ 6,546:
=={{header|Sidef}}==
{{trans|Perl}}
<
txt.trim!
Line 6,366 ⟶ 6,595:
say s # dump structure
say sexpr2txt(s) # convert back</
{{out}}
<pre>
Line 6,375 ⟶ 6,604:
=={{header|Tcl}}==
Note that because Tcl doesn't expose a type system (well, not in a conventional sense) the parts of the parsed out data structure are tagged lists; the first element is one of “<tt>string</tt>”, “<tt>int</tt>”, “<tt>real</tt>” and “<tt>atom</tt>” to indicate a leaf token, or “<tt>list</tt>” to indicate a sublist. A “native” data structure could also be generated, but then that would turn things into lists that are not in the original.
<
proc fromSexp {str} {
Line 6,423 ⟶ 6,652:
return [lindex $content 0]
}
}</
Demonstrating with the sample data:
<
(data (!@# (4.5) "(more" "data)")))}
set parsed [fromSexp $sample]
puts "sample: $sample"
puts "parsed: $parsed"
puts "regen: [toSexp $parsed]"</
Output:
<pre>
Line 6,476 ⟶ 6,705:
Code:
<
@(local (tok))@\
@(cases)@\
Line 6,519 ⟶ 6,748:
expr: @(format nil "~s" e)
junk: @junk
@(end)</
Run:
Line 6,554 ⟶ 6,783:
Explanation of most confusing line:
<
First, we match an open parenthesis that can be embedded in whitespace. Then we have a <code>@(coll)</code> construct which terminates with <code>@(end)</code>. This is a repetition construct for collecting zero or more items. The <code>:vars (e)</code> argument makes the collect strict: each repetition must bind the variable <code>e</code>. More importantly, in this case, if nothing is
Line 6,563 ⟶ 6,792:
{{libheader|Wren-pattern}}
{{libheader|Wren-fmt}}
<
import "./fmt" for Fmt
var INDENT = 2
Line 6,650 ⟶ 6,879:
System.print("\nRecovered S-Expression (pretty print):")
prettyPrint.call(tokens)
}</
{{out}}
|