arturo-lang / arturo

Simple, expressive & portable programming language for efficient scripting
http://arturo-lang.io
MIT License
718 stars 32 forks source link

renderTemplate does not respect newlines in multi-line input #216

Closed github-actions[bot] closed 3 years ago

github-actions[bot] commented 3 years ago

renderTemplate does not respect newlines in multi-line input

check templates.art for the inconsistency

https://github.com/arturo-lang/arturo/blob/ce74178361b35adf49baa85b3f6c0bbf29dad967/src/helpers/templates.nim#L48

# Arturo
# Programming Language + Bytecode VM compiler
# (c) 2019-2021 Yanis Zafirópulos
#
# @file: helpers/templates.nim
######################################################

#=======================================
# Libraries
#=======================================

import sequtils, strutils, tables
import nre except toSeq

import vm/[exec, parse, stack, value]

#=======================================
# Constants
#=======================================

var
    Interpolated    = nre.re"\|([^\|]+)\|"
    Embeddable      = nre.re"(\<\|.*?\|\>)"

#=======================================
# Helpers
#=======================================

proc renderInterpolated(s: string, recursive: bool, useReference: bool, reference: ValueDict): string =
    result = s

    var keepGoing = true
    if recursive: 
        keepGoing = result.find(Interpolated).isSome

    while keepGoing:
        result = result.replace(Interpolated, proc (match: RegexMatch): string =
                        discard execBlock(doParse(match.captures[0], isFile=false))
                        $(stack.pop())
                    )

        # if recursive, check if there's still more embedded tags
        # otherwise, break out of the loop
        if recursive: keepGoing = result.find(Interpolated).isSome
        else: keepGoing = false

# TODO renderTemplate does not respect newlines in multi-line input
#  check `templates.art` for the inconsistency
proc renderTemplate(s: string, recursive: bool, useReference: bool, reference: ValueDict): string =
    result = s

    var keepGoing = true
    if recursive: 
        keepGoing = result.find(Embeddable).isSome

    while keepGoing:
        # split input by tags
        var splitted = result.split(Embeddable)

        var blk: seq[string] = @[]

        # go through the token one-by-one
        for i,spl in splitted:

            if spl.match(Embeddable).isNone:
                # if it's not an embedded tag,
                # added as a string - split by lines
                blk.add(codify(newString(spl), safeStrings=true))
                # let stripped = spl.strip()
                # if stripped != "" and (stripped[^1] in {'\r','\n'}):
                #         blk.add("\"\\n\"")
            else:
                # otherwise, clean it up
                var parseable = spl.strip(chars = {'<', '>', '|'})
                var output = false
                if parseable[0] == '=': 
                    output = true
                    parseable = parseable.strip(chars = {'='})

                # if it's a <|: something |> tag, stringify it
                if output:
                    blk.add("to")
                    blk.add(":string")

                blk.add(parseable)

        let subscript = blk.join(" ")
        let parsed = doParse(subscript, isFile=false)

        # execute/reduce ('array') the resulting block
        let stop = SP
        discard execBlock(parsed)
        let arr: ValueArray = sTopsFrom(stop)
        SP = stop

        # and join the different strings
        result = arr.map(proc (v:Value):string = v.s).join()

        # if recursive, check if there's still more embedded tags
        # otherwise, break out of the loop
        if recursive: keepGoing = result.find(Embeddable).isSome
        else: keepGoing = false

#=======================================
# Methods
#=======================================

proc renderString*(s: string, useEngine: bool = false, recursive: bool = false, reference: ValueDict = initOrderedTable[string,Value]()): string =
    if useEngine:
        renderTemplate(s, recursive, (len(reference)>0), reference)
    else:
        renderInterpolated(s, recursive, (len(reference)>0), reference)

ndex 6e696754..75e4cab6 100644
++ b/src/library/Collections.nim

c4cc03c84286cbb436edce285f0e2a9cd1f00bf6

drkameleon commented 3 years ago

Issues has been already fixed in previous PR: #206