All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lux.parser.clj Maven / Gradle / Ivy

The newest version!
;;  Copyright (c) Eduardo Julian. All rights reserved.
;;  This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
;;  If a copy of the MPL was not distributed with this file,
;;  You can obtain one at http://mozilla.org/MPL/2.0/.

(ns lux.parser
  (:require [clojure.template :refer [do-template]]
            clojure.core.match
            clojure.core.match.array
            (lux [base :as & :refer [|do return |case]]
                 [lexer :as &lexer])))

;; [Utils]
(def ^:private base-uneven-record-error
  "[Parser Error] Records must have an even number of elements.")

(defn ^:private repeat% [action]
  (fn [state]
    (|case (action state)
      (&/$Left ^String error)
      (cond (.contains error base-uneven-record-error)
            (&/$Left error)

            (not (.contains error "[Parser Error]"))
            (&/$Left error)

            :else
            (&/$Right (&/T [state &/$Nil])))

      (&/$Right state* head)
      ((|do [tail (repeat% action)]
         (return (&/$Cons head tail)))
       state*))))

(do-template [   ]
  (defn  [parse]
    (|do [elems (repeat% parse)
          token &lexer/lex]
      (|case token
        [meta ( _)]
        (return ( (&/fold &/|++ &/$Nil elems)))
        
        _
        (&/fail-with-loc (str "[Parser Error] Unbalanced "  "."))
        )))

  ^:private parse-form  &lexer/$Close_Paren   "parantheses" &/$FormS
  ^:private parse-tuple &lexer/$Close_Bracket "brackets"    &/$TupleS
  )

(defn ^:private parse-record [parse]
  (|do [elems* (repeat% parse)
        token &lexer/lex
        :let [elems (&/fold &/|++ &/$Nil elems*)]]
    (|case token
      [meta (&lexer/$Close_Brace _)]
      (if (even? (&/|length elems))
        (return (&/$RecordS (&/|as-pairs elems)))
        (&/fail-with-loc base-uneven-record-error))
      
      _
      (&/fail-with-loc "[Parser Error] Unbalanced braces.")
      )))

;; [Interface]
(def parse
  (|do [token &lexer/lex
        :let [[meta token*] token]]
    (|case token*
      (&lexer/$White_Space _)
      (return &/$Nil)

      (&lexer/$Comment _)
      (return &/$Nil)
      
      (&lexer/$Bool ?value)
      (return (&/|list (&/T [meta (&/$BoolS (Boolean/parseBoolean ?value))])))

      (&lexer/$Nat ?value)
      (return (&/|list (&/T [meta (&/$NatS (Long/parseUnsignedLong ?value))])))

      (&lexer/$Int ?value)
      (return (&/|list (&/T [meta (&/$IntS (Long/parseLong ?value))])))

      (&lexer/$Frac ?value)
      (return (&/|list (&/T [meta (&/$FracS (&/decode-frac ?value))])))

      (&lexer/$Real ?value)
      (return (&/|list (&/T [meta (&/$RealS (Double/parseDouble ?value))])))

      (&lexer/$Char ^String ?value)
      (return (&/|list (&/T [meta (&/$CharS (.charAt ?value 0))])))

      (&lexer/$Text ?value)
      (return (&/|list (&/T [meta (&/$TextS ?value)])))

      (&lexer/$Symbol ?ident)
      (return (&/|list (&/T [meta (&/$SymbolS ?ident)])))

      (&lexer/$Tag ?ident)
      (return (&/|list (&/T [meta (&/$TagS ?ident)])))

      (&lexer/$Open_Paren _)
      (|do [syntax (parse-form parse)]
        (return (&/|list (&/T [meta syntax]))))
      
      (&lexer/$Open_Bracket _)
      (|do [syntax (parse-tuple parse)]
        (return (&/|list (&/T [meta syntax]))))

      (&lexer/$Open_Brace _)
      (|do [syntax (parse-record parse)]
        (return (&/|list (&/T [meta syntax]))))

      _
      (&/fail-with-loc "[Parser Error] Unknown lexer token.")
      )))




© 2015 - 2024 Weber Informatics LLC | Privacy Policy