mirror of
https://github.com/fluencelabs/aqua.git
synced 2025-04-25 06:52:13 +00:00
This commit is contained in:
parent
dc1f6c2faa
commit
7362b46384
@ -1,7 +1,12 @@
|
||||
module Import
|
||||
service SomeService("erf"):
|
||||
someCall()
|
||||
|
||||
use "export.aqua"
|
||||
func string_nil() -> *string:
|
||||
value_nil: *string
|
||||
SomeService.someCall()
|
||||
<- value_nil
|
||||
|
||||
func foo_wrapper() -> string:
|
||||
z <- Export.foo()
|
||||
<- z
|
||||
func post() -> *string:
|
||||
relay_nil: **string
|
||||
relay_nil <- string_nil()
|
||||
<- relay_nil
|
@ -29,7 +29,7 @@ object JavaScriptCommon {
|
||||
.concat(List("callParams"))
|
||||
.mkString(", ")
|
||||
|
||||
val callCallbackStatement = s"$callbackName(${arrowArgumentsToCallbackArgumentsList})"
|
||||
val callCallbackStatement = s"$callbackName($arrowArgumentsToCallbackArgumentsList)"
|
||||
|
||||
val callCallbackStatementAndReturn =
|
||||
at.res.fold(s"${callCallbackStatement}; resp.result = {}")(`type` =>
|
||||
|
@ -3,41 +3,68 @@ package aqua
|
||||
import aqua.compiler.*
|
||||
import aqua.files.FileModuleId
|
||||
import aqua.io.AquaFileError
|
||||
import aqua.parser.lift.FileSpan
|
||||
import aqua.parser.lift.{FileSpan, Span}
|
||||
import aqua.parser.{BlockIndentError, FuncReturnError, LexerError}
|
||||
import aqua.semantics.{HeaderError, RulesViolated, WrongAST}
|
||||
import cats.Show
|
||||
import cats.{Eval, Show}
|
||||
import cats.parse.LocationMap
|
||||
import cats.parse.Parser.Expectation
|
||||
import cats.parse.Parser.Expectation.*
|
||||
|
||||
object ErrorRendering {
|
||||
|
||||
def showForConsole(span: FileSpan, message: String): String =
|
||||
def expectationToString(expectation: Expectation, locationMap: Eval[LocationMap], currentOffset: Int): String = {
|
||||
// add column number if it is not on the current offset
|
||||
def makeMsg(msg: String, offset: Int): String = {
|
||||
if (offset == currentOffset) msg
|
||||
else {
|
||||
val focus = Span(offset, offset + 1).focus(locationMap, 0)
|
||||
focus.map(f => s"$msg on ${f.line._1}:${f.column}").getOrElse(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: match all expectations
|
||||
expectation match {
|
||||
case wc@WithContext(str, offset) => makeMsg(str, wc.offset)
|
||||
case InRange(offset, lower, upper) =>
|
||||
if (lower == upper)
|
||||
makeMsg(s"Expected symbol '$lower'", offset)
|
||||
else
|
||||
makeMsg(s"Expected symbols from '$lower' to '$upper'", offset)
|
||||
case OneOfStr(offset, strs) =>
|
||||
makeMsg(s"Expected one of these strings: ${strs.map(s => s"'$s'").mkString(", ")}", offset)
|
||||
case e => "Expected: " + e.toString
|
||||
}
|
||||
}
|
||||
|
||||
def showForConsole(span: FileSpan, messages: List[String]): String =
|
||||
span
|
||||
.focus(3)
|
||||
.map(
|
||||
_.toConsoleStr(
|
||||
message,
|
||||
messages,
|
||||
Console.RED
|
||||
)
|
||||
)
|
||||
.getOrElse(
|
||||
"(offset is beyond the script, syntax errors) Error: " + Console.RED + message
|
||||
.mkString(", ")
|
||||
"(offset is beyond the script, syntax errors) Error: " + Console.RED + messages.mkString(", ")
|
||||
) + Console.RESET + "\n"
|
||||
|
||||
implicit val showError: Show[AquaError[FileModuleId, AquaFileError, FileSpan.F]] = Show.show {
|
||||
case ParserErr(err) =>
|
||||
err match {
|
||||
case BlockIndentError(indent, message) => showForConsole(indent._1, message)
|
||||
case FuncReturnError(point, message) => showForConsole(point._1, message)
|
||||
case BlockIndentError(indent, message) => showForConsole(indent._1, message :: Nil)
|
||||
case FuncReturnError(point, message) => showForConsole(point._1, message :: Nil)
|
||||
case LexerError((span, e)) =>
|
||||
span
|
||||
.focus(3)
|
||||
.map(spanFocus =>
|
||||
.map { spanFocus =>
|
||||
val errorMessages = e.expected.map(exp => expectationToString(exp, span.locationMap, span.span.startIndex))
|
||||
spanFocus.toConsoleStr(
|
||||
s"Syntax error, expected: ${e.expected.toList.mkString(", ")}",
|
||||
s"Syntax error: ${errorMessages.head}" :: errorMessages.tail.map(t => "OR " + t),
|
||||
Console.RED
|
||||
)
|
||||
)
|
||||
}
|
||||
.getOrElse(
|
||||
"(offset is beyond the script, syntax errors) " + Console.RED + e.expected.toList
|
||||
.mkString(", ")
|
||||
@ -47,11 +74,11 @@ object ErrorRendering {
|
||||
Console.RED + err.showForConsole + Console.RESET
|
||||
case ResolveImportsErr(_, token, err) =>
|
||||
val span = token.unit._1
|
||||
showForConsole(span, s"Cannot resolve imports: ${err.showForConsole}")
|
||||
showForConsole(span, s"Cannot resolve imports: ${err.showForConsole}" :: Nil)
|
||||
|
||||
case ImportErr(token) =>
|
||||
val span = token.unit._1
|
||||
showForConsole(span, s"Cannot resolve import")
|
||||
showForConsole(span, s"Cannot resolve import" :: Nil)
|
||||
case CycleError(modules) =>
|
||||
s"Cycle loops detected in imports: ${modules.map(_.file.fileName)}"
|
||||
case CompileError(err) =>
|
||||
@ -59,12 +86,12 @@ object ErrorRendering {
|
||||
case RulesViolated(token, message) =>
|
||||
token.unit._1
|
||||
.focus(2)
|
||||
.map(_.toConsoleStr(message, Console.CYAN))
|
||||
.map(_.toConsoleStr(message :: Nil, Console.CYAN))
|
||||
.getOrElse("(Dup error, but offset is beyond the script)") + "\n"
|
||||
case HeaderError(token, message) =>
|
||||
token.unit._1
|
||||
.focus(2)
|
||||
.map(_.toConsoleStr(message, Console.CYAN))
|
||||
.map(_.toConsoleStr(message :: Nil, Console.CYAN))
|
||||
.getOrElse("(Dup error, but offset is beyond the script)") + "\n"
|
||||
case WrongAST(ast) =>
|
||||
s"Semantic error"
|
||||
|
@ -30,13 +30,14 @@ case class FuncCallable(
|
||||
.head)
|
||||
}
|
||||
|
||||
def extractStreamArgs(args: Map[String, ValueModel]): Map[String, ValueModel] =
|
||||
args.filter { arg =>
|
||||
arg._2.`type` match {
|
||||
def isStream(vm: ValueModel): Boolean =
|
||||
vm.`type` match {
|
||||
case StreamType(_) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def extractStreamArgs(args: Map[String, ValueModel]): Map[String, ValueModel] =
|
||||
args.filter(arg => isStream(arg._2))
|
||||
|
||||
// Apply a callable function, get its fully resolved body & optional value, if any
|
||||
def resolve(
|
||||
@ -153,7 +154,10 @@ case class FuncCallable(
|
||||
|
||||
val (ops, rets) = (call.exportTo zip resolvedResult)
|
||||
.map[(Option[FuncOp], ValueModel)] {
|
||||
case (exp @ Call.Export(_, StreamType(_)), res) if isStream(res) =>
|
||||
None -> res
|
||||
case (exp @ Call.Export(_, StreamType(_)), res) =>
|
||||
res.`type`
|
||||
// pass nested function results to a stream
|
||||
Some(FuncOps.ap(res, exp)) -> exp.model
|
||||
case (_, res) =>
|
||||
|
@ -1,13 +1,13 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.Token.*
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import aqua.parser.lift.LiftParser.*
|
||||
import aqua.types.ScalarType
|
||||
import cats.Comonad
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.comonad._
|
||||
import cats.syntax.functor._
|
||||
import cats.parse.{Accumulator0, Parser as P}
|
||||
import cats.syntax.comonad.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.~>
|
||||
|
||||
sealed trait TypeToken[F[_]] extends Token[F] {
|
||||
@ -40,7 +40,9 @@ case class StreamTypeToken[F[_]: Comonad](override val unit: F[Unit], data: Data
|
||||
object StreamTypeToken {
|
||||
|
||||
def `streamtypedef`[F[_]: LiftParser: Comonad]: P[StreamTypeToken[F]] =
|
||||
(`*`.lift ~ DataTypeToken.`datatypedef`[F]).map(ud => StreamTypeToken(ud._1, ud._2))
|
||||
((`*`.lift <* P.not(`*`).withContext("Nested streams '**type' is prohibited"))
|
||||
~ DataTypeToken.`withoutstreamdatatypedef`[F])
|
||||
.map(ud => StreamTypeToken(ud._1, ud._2))
|
||||
|
||||
}
|
||||
|
||||
@ -137,6 +139,14 @@ object DataTypeToken {
|
||||
`⊥`.lift.map(TopBottomToken(_, isTop = false)) |
|
||||
`⊤`.lift.map(TopBottomToken(_, isTop = true))
|
||||
|
||||
def `withoutstreamdatatypedef`[F[_]: LiftParser: Comonad]: P[DataTypeToken[F]] =
|
||||
P.oneOf(
|
||||
P.defer(`arraytypedef`[F]) :: P.defer(
|
||||
OptionTypeToken.`optiontypedef`
|
||||
) :: BasicTypeToken
|
||||
.`basictypedef`[F] :: CustomTypeToken.dotted[F] :: Nil
|
||||
)
|
||||
|
||||
def `datatypedef`[F[_]: LiftParser: Comonad]: P[DataTypeToken[F]] =
|
||||
P.oneOf(
|
||||
P.defer(`arraytypedef`[F]) :: P.defer(StreamTypeToken.`streamtypedef`) :: P.defer(
|
||||
|
@ -17,10 +17,10 @@ object FileSpan {
|
||||
|
||||
case class Focus(name: String, locationMap: Eval[LocationMap], ctx: Int, spanFocus: Span.Focus) {
|
||||
|
||||
def toConsoleStr(msg: String, onLeft: String, onRight: String = Console.RESET): String =
|
||||
def toConsoleStr(msgs: List[String], onLeft: String, onRight: String = Console.RESET): String =
|
||||
s"$name:${spanFocus.line._1 + 1}:${spanFocus.column + 1}\n" +
|
||||
spanFocus.toConsoleStr(
|
||||
msg,
|
||||
msgs,
|
||||
onLeft,
|
||||
onRight
|
||||
)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package aqua.parser.lift
|
||||
|
||||
import cats.parse.{LocationMap, Parser0, Parser => P}
|
||||
import cats.data.NonEmptyList
|
||||
import cats.parse.{LocationMap, Parser0, Parser as P}
|
||||
import cats.{Comonad, Eval}
|
||||
|
||||
import scala.language.implicitConversions
|
||||
@ -54,12 +55,13 @@ object Span {
|
||||
}
|
||||
|
||||
def toConsoleStr(
|
||||
msg: String,
|
||||
msgs: List[String],
|
||||
onLeft: String,
|
||||
onRight: String = Console.RESET
|
||||
): String = {
|
||||
val line3Length = line._3.length
|
||||
val line3Mult = if (line3Length == 0) 1 else line3Length
|
||||
val message = msgs.map(m => (" " * (line._2.length + lastNSize + 1)) + m).mkString("\n")
|
||||
pre.map(formatLine(_, onLeft, onRight)).mkString("\n") +
|
||||
"\n" +
|
||||
formatLN(line._1, onLeft, onRight) +
|
||||
@ -75,9 +77,8 @@ object Span {
|
||||
("=" * line._4.length) +
|
||||
onRight +
|
||||
"\n" +
|
||||
(" " * (line._2.length + lastNSize + 1)) +
|
||||
onLeft +
|
||||
msg +
|
||||
message +
|
||||
onRight +
|
||||
"\n" +
|
||||
post.map(formatLine(_, onLeft, onRight)).mkString("\n")
|
||||
@ -106,8 +107,15 @@ object Span {
|
||||
(Span(i, i), v)
|
||||
}
|
||||
|
||||
override def wrapErr(e: P.Error): (Span, P.Error) =
|
||||
(Span(e.failedAtOffset, e.failedAtOffset + 1), e)
|
||||
override def wrapErr(e: P.Error): (Span, P.Error) = {
|
||||
// Find all WithContext expectations, get last by offset.
|
||||
// This will be the final error handled by hand.
|
||||
val withContext = e.expected.collect {
|
||||
case e@P.Expectation.WithContext(_, _) => e
|
||||
}.sortBy(_.offset).headOption
|
||||
val exp = withContext.map(e => P.Error(e.offset, NonEmptyList.one(e))).getOrElse(e)
|
||||
(Span(exp.failedAtOffset, exp.failedAtOffset + 1), exp)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user