From f0099384d94a6a424e798f9019e3fad691406e83 Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Thu, 31 Dec 2015 20:25:24 -0400 Subject: - Implemented multi-line text literals. --- src/lux/lexer.clj | 56 +++++++++++++++++++++++++++++++++++++++++-------- src/lux/type/host.clj | 2 +- test/test/lux/lexer.clj | 17 ++++++++++----- 3 files changed, 60 insertions(+), 15 deletions(-) diff --git a/src/lux/lexer.clj b/src/lux/lexer.clj index e82e22ee4..0200ef8a9 100644 --- a/src/lux/lexer.clj +++ b/src/lux/lexer.clj @@ -4,7 +4,8 @@ ;; You can obtain one at http://mozilla.org/MPL/2.0/. (ns lux.lexer - (:require [clojure.template :refer [do-template]] + (:require (clojure [template :refer [do-template]] + [string :as string]) (lux [base :as & :refer [deftags |do return* return fail fail*]] [reader :as &reader]) [lux.analyser.module :as &module])) @@ -40,13 +41,50 @@ :else (fail (str "[Lexer Error] Unknown escape character: " escaped)))) -(defn ^:private lex-text-body [_] - (&/try-all% (&/|list (|do [[_ [prefix escaped]] (&reader/read-regex2 #"(?s)^([^\"\\]*)(\\.)") - unescaped (escape-char escaped) - postfix (lex-text-body nil)] - (return (str prefix unescaped postfix))) - (|do [[_ body] (&reader/read-regex #"(?s)^([^\"\\]*)")] - (return body))))) +(defn ^:private escape-char* [escaped] + (cond (.equals ^Object escaped "\\t") "\t" + (.equals ^Object escaped "\\b") "\b" + (.equals ^Object escaped "\\n") "\n" + (.equals ^Object escaped "\\r") "\r" + (.equals ^Object escaped "\\f") "\f" + (.equals ^Object escaped "\\\"") "\"" + (.equals ^Object escaped "\\\\") "\\" + :else + (assert false (str "[Lexer Error] Unknown escape character: " escaped)))) + +(defn ^:private clean-line [raw-line] + (string/replace raw-line #"\\." escape-char*)) + +(def ^:private lex-text-line + (&reader/read-regex #"^(.*) \\$")) + +(def ^:private lext-text-line-prefix + (&reader/read-regex #"^(\s*\\ )")) + +(defn ^:private lex-text-next-line [within-multiline? lex-text-body] + (&/try-all% (&/|list (if within-multiline? + (|do [[_ blank-line] (&reader/read-regex #"^()$") + next-part (lex-text-next-line within-multiline? lex-text-body)] + (return (str "\n" next-part))) + (fail "")) + (|do [[_ line-prefix] lext-text-line-prefix + next-part lex-text-body] + (return (str "\n" next-part)))))) + +(defn ^:private lex-text-body [within-multiline?] + (&/try-all% (&/|list (|do [[_ ^String this-line*] lex-text-line + :let [this-line (.substring this-line* 0 (- (.length this-line*) 2))] + next-lines (lex-text-next-line true (lex-text-body true))] + (return (str (clean-line this-line) + next-lines)) + ) + (|do [[_ ^String pre-quotes] (&reader/read-regex #"^([^\"]*)") + post-quotes (if (.endsWith pre-quotes "\\") + (|do [_ (&reader/read-regex #"^([\"])") + next-part (lex-text-body within-multiline?)] + (return (str "\"" next-part))) + (return ""))] + (return (clean-line (str pre-quotes post-quotes))))))) (def ^:private +ident-re+ #"^([a-zA-Z\-\+\_\=!@$%^&*<>\.,/\\\|'`:\~\?][0-9a-zA-Z\-\+\_\=!@$%^&*<>\.,/\\\|'`:\~\?]*)" ;; #"^([^0-9\[\]\(\)\{\};#\s\"][^\[\]\(\)\{\};#\s\"]*)" @@ -98,7 +136,7 @@ (def ^:private lex-text (|do [[meta _] (&reader/read-text "\"") - token (lex-text-body nil) + token (lex-text-body false) _ (&reader/read-text "\"")] (return (&/T meta (&/V $Text token))))) diff --git a/src/lux/type/host.clj b/src/lux/type/host.clj index ddb40f21d..9a7546ca4 100644 --- a/src/lux/type/host.clj +++ b/src/lux/type/host.clj @@ -237,7 +237,7 @@ (defn gtype->gclass [gtype] "(-> GenericType GenericClass)" (cond (instance? Class gtype) - (&/V &/$GenericClass (&/T (.getName gtype) &/Nil$)) + (&/V &/$GenericClass (&/T (.getName ^Class gtype) &/Nil$)) (instance? GenericArrayType gtype) (&/V &/$GenericArray (gtype->gclass (.getGenericComponentType ^GenericArrayType gtype))) diff --git a/test/test/lux/lexer.clj b/test/test/lux/lexer.clj index 72602639d..dc00c1d51 100644 --- a/test/test/lux/lexer.clj +++ b/test/test/lux/lexer.clj @@ -160,19 +160,26 @@ (deftest lex-text (let [input1 "" input2 "abc" - input3 "yolo\\nlol\\tmeme"] + input3 "yolo\\nlol\\tmeme" + input4 "This is a test \\ + \\ of multi-line text. \\ + + \\ I just wanna make sure it works alright..."] (|case (&/run-state (|do [[_ output1] &lexer/lex [_ output2] &lexer/lex - [_ output3] &lexer/lex] - (return (&/T output1 output2 output3))) + [_ output3] &lexer/lex + [_ output4] &lexer/lex] + (return (&/T output1 output2 output3 output4))) (make-state (str "\"" input1 "\"" "\n" "\"" input2 "\"" "\n" "\"" input3 "\""))) (&/$Right state [(&lexer/$Text output1) (&lexer/$Text output2) - (&lexer/$Text output3)]) + (&lexer/$Text output3) + (&lexer/$Text output4)]) (are [input output] (= input output) input1 output1 input2 output2 - "yolo\nlol\tmeme" output3) + "yolo\nlol\tmeme" output3 + "This is a test\nof multi-line text.\n\nI just wanna make sure it works alright..." output4) _ (is false "Couldn't read.") -- cgit v1.2.3