Макрос Scala 3 для отображения исходного кода файла

Я разрабатываю библиотеку и хочу продемонстрировать код на небольшом веб-сайте. Фрагменты кода должны быть получены непосредственно из одного и того же проекта, т. е. код должен ссылаться на самого себя.

Я хочу написать макрос, который, учитывая файл или имя класса, возвращает строку с содержимым файла. Как я могу этого добиться?

Предположим, ваш макрос inline def getContent(filePath: String): String = ${getContentImpl('className)}. Является ли filePath строкой времени компиляции (как в getContent("path/to/file")) или строкой времени выполнения (как в val str = "path/to/file"; getContent(str))?

Dmytro Mitin 18.02.2023 22:59

Почему вы хотите, чтобы это был макрос? Почему это не может быть обычным методом?

Dmytro Mitin 18.02.2023 23:01

Файлы не существуют во время выполнения. Они являются источником запущенного приложения.

Felix 19.02.2023 07:41

Я бы также согласился указать имя класса или тип в качестве аргумента и вернуть источник класса/объекта/признака или что-то еще, что реализовало этот тип.

Felix 19.02.2023 07:43

«Файлы не существуют во время выполнения». Почему? Вы удаляете исходники после компиляции?

Dmytro Mitin 19.02.2023 10:00

Почему бы не запустить компилятор scala во время выполнения и не скомпилировать все необходимые фрагменты кода?

Dmytro Mitin 19.02.2023 11:38

Файлы существуют во время выполнения, но приложение теряет их из виду. Запуск компилятора во время выполнения вызовет столько проблем, что я даже не знаю, с чего начать. Ваш ответ ниже, кажется, то, что мне нужно - я вернусь, как только у меня будет возможность проверить его: D Спасибо!

Felix 20.02.2023 08:16
Конечные и Readonly классы в PHP
Конечные и Readonly классы в PHP
В прошлом, когда вы не хотели, чтобы другие классы расширяли определенный класс, вы могли пометить его как final.
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
Если вы уже умеете работать с React, создание мобильных приложений для iOS и Android - это новое приключение, в котором вы сможете применить свои...
БЭМ: Конвенция об именовании CSS
БЭМ: Конвенция об именовании CSS
Я часто вижу беспорядочный код CSS, особенно если проект большой. Кроме того, я совершал эту ошибку в профессиональных или личных проектах и...
Революционная веб-разработка ServiceNow
Революционная веб-разработка ServiceNow
В быстро развивающемся мире веб-разработки ServiceNow для достижения успеха крайне важно оставаться на вершине последних тенденций и технологий. По...
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Заголовок веб-страницы играет наиболее важную роль в SEO, он помогает поисковой системе понять, о чем ваш сайт.
Конфигурация Jest в angular
Конфигурация Jest в angular
В этой статье я рассказываю обо всех необходимых шагах, которые нужно выполнить при настройке jest в angular.
0
7
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
Я бы также согласился указать имя класса или тип в качестве аргумента

Вы ищете такой макрос?

import scala.quoted.*

inline def getContent[A]: String = ${getContentImpl[A]}

def getContentImpl[A: Type](using Quotes): Expr[String] =
  import quotes.reflect.*

     // for the source specifically of A
  // val str = TypeRepr.of[A].typeSymbol.tree.pos.sourceCode.getOrElse(
  //   report.errorAndAbort("no source code")
  // )

     // for the whole source file containing the definition of A
  val str = TypeRepr.of[A].typeSymbol.pos.getOrElse(
    report.errorAndAbort("no symbol position")
  ).sourceFile.content.getOrElse(
    report.errorAndAbort("no source-file content")
  )

  Expr(str)
// in a different file

getContent[A]

//import Macros.getContent
//
//object Main extends App {
//  class A:
//    def foo = 1
//
//  println(
//    getContent[A]
//  )
//}

Как преобразовать блок кода scala в строку? (Скала 2)

Это действительно хорошо, спасибо!

Felix 20.02.2023 09:18

У меня проблема - иногда не получается и позиция печатается как "?", есть идеи?

Felix 20.02.2023 15:24

@ Феликс Нет. Странно. Если исходный код недоступен, он не должен компилироваться и возвращать ?. Попробуйте создать репродукцию

Dmytro Mitin 20.02.2023 15:51
gist.github.com/hejfelix/24a59869231cf435a03370bd03d361ec первый раз запускаю в sbt, работает как положено и печатает: " class Foo[F[_]] { } " в следующий раз, если я вставлю перенос строки или что-нибудь доброкачественное изменить, он печатает пустую строку без ошибок. report.info показывает, что позиция "?" а исходный файл "NoFile" пахнет ошибкой кэширования.
Felix 20.02.2023 19:01

Очистка и перекомпиляция вроде бы исправляют, но потом снова быстро ломаются.

Felix 20.02.2023 21:47

У меня есть репозиторий для воспроизведения проблемы здесь: github.com/hejfelix/macro-repro

Felix 21.02.2023 11:41

@Felix Чистая компиляция является хорошей практикой при работе со сгенерированным кодом. Поведение в Scala 2 такое же gist.github.com/DmytroMitin/344f2d1410b4f285bc95b8299f9096aa Подозреваю, что это не баг, а то, как sbt + цинк управляют инкрементной компиляцией. При чистой компиляции sbt пишет compiling 3 Scala sources, при перекомпиляции после модификации SourceMacro пишет compiling 1 Scala source, compiling 1 Scala source. Думаю, это влияет на позицию.

Dmytro Mitin 21.02.2023 18:34

@Felix Почему чистая компиляция является проблемой для вашего варианта использования?

Dmytro Mitin 21.02.2023 18:35

Я полагаю, вы правы. Это просто раздражает при отладке/разработке. Последний артефакт исходит от CI, который в настоящее время выполняет чистую компиляцию, поэтому все должно быть в порядке. Спасибо за изучение этого, я повторно принял 👌

Felix 22.02.2023 06:23

Другие вопросы по теме